如何将对父 class 的所有呼叫转移到子 class?
How to divert all calls to parent class to child class?
假设我有一个引用包含 Class1 的 dll 的 C# 项目。在 Project1 中,我想通过使用继承自 Class1 的名为 Class2 的 class 来扩展 Class1 的功能,然后我想在需要 Class1 时使用 Class2( 而无需将对 Class1 的调用修改为指向Class2,这是key)。
此外,我必须添加 Class1 是一个初始化模块(在我正在使用的框架中),它没有被显式调用(它是内部机制的一部分)。
这意味着在我的代码中让 Class2 扩展了 Class1 的行为后,我不能简单地去替换 Class2 对 Class1 的调用。
(如何)可以做到这一点?
我想到的另一个想法是使用部分 classes;但是,我怀疑是否有可能在该 dll 之外将完整的 class 重新定义为 'later' 的部分 class。
===== 后来编辑:我看到一篇文章似乎暗示这是可能的,我正在尝试弄清楚如何做到这一点。看,在这篇文章中,它具有从 dll 中的 IInitializableModule (Class1) 继承的 RestrictFileTypes (Class2),但它没有说明 Class2 从那时起如何替换 Class1 的所有调用,向前发展 (http://world.episerver.com/blogs/al-higgs/dates/2012/11/Restricting-the-file-types/)。你怎么看待它?
我不明白第二个要求("Moreoever...")。至于第一个,我看到了两种方式。
您可以编写class2,然后通过手动编辑交换class1 和class2 的名称。出现的次数应该很少,只有 cs 文件名和构造函数。像您通常在交换操作中所做的那样,首先使用中间名称可能会省事。这可能是最简单和最干净的方法,但您可能无法控制当前的 class1 并且无法重命名它。所以这是另一种方式。
您从头开始再次将 class2 命名为 class1,但在不同的命名空间中。您将有一个 class1 从不同命名空间中的另一个 class1(旧的)下降。完成后,在每个引用旧 class1 的文件中为新命名空间放置一个 using 指令,并确保它是最后一个 using 行,以便它优先于它上面的那些。如果当前 class1 不是引用它的同一个命名空间的成员,这应该有效。如果是后者,则必须将新名称空间的声明插入到现有名称空间的所有声明中:
namespace ns.of.old.class1
{
namespace ns.of.new.class1
{
[...]
Some reference to / use of class1
}
}
using 指令技巧很脆弱,有人可能会注意到指令不是按字母顺序排列的,然后右键单击它们,选择 "Remove and Sort"。然后您的代码可能会被破坏或更糟:仍然可以编译但再次使用旧的 class1。
我称之为 多态性 并通过继承实现,如下所示:
using System;
namespace polymorphismExample {
public class class1 {
public virtual string A => "I am Class1.A";
public string B => "I am Class1.B";
}
public class class2 : class1 {
public override string A => "I am Class2.A";
// public override string B => "I am Class1.B";
public new string B => "I am Class2.B";
}
class Program {
static void Main(string[] args) {
class1 a1_1 = new class1();
class1 b1_2 = new class2();
class2 b2_2 = new class2();
Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.A);
Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.B);
Console.WriteLine();
Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.A);
Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.B);
Console.WriteLine();
Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.A);
Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.B);
Console.WriteLine();
Console.ReadLine();
}
}
}
输出为:
a1_1.A: I am Class1.A
a1_1.A: I am Class1.B
b1_2.A: I am Class2.A
b1_2.A: I am Class1.B
b2_2.A: I am Class2.A
b2_2.A: I am Class2.B
注意class2
中的注释行是因为不能编译;因为方法 B 在 class1
中不是虚拟的。此模式要求 class1
不是 密封的 class,并且只有 class1
中的方法被标记为 虚拟(或者当然是 abstract)将表现出所需的行为:即使在声明为 class1
类型的变量上调用时也会调用 class2
行为.
当然,在任何时候,变量都必须使用 class2
构造函数进行初始化。
假设我有一个引用包含 Class1 的 dll 的 C# 项目。在 Project1 中,我想通过使用继承自 Class1 的名为 Class2 的 class 来扩展 Class1 的功能,然后我想在需要 Class1 时使用 Class2( 而无需将对 Class1 的调用修改为指向Class2,这是key)。
此外,我必须添加 Class1 是一个初始化模块(在我正在使用的框架中),它没有被显式调用(它是内部机制的一部分)。 这意味着在我的代码中让 Class2 扩展了 Class1 的行为后,我不能简单地去替换 Class2 对 Class1 的调用。
(如何)可以做到这一点?
我想到的另一个想法是使用部分 classes;但是,我怀疑是否有可能在该 dll 之外将完整的 class 重新定义为 'later' 的部分 class。
===== 后来编辑:我看到一篇文章似乎暗示这是可能的,我正在尝试弄清楚如何做到这一点。看,在这篇文章中,它具有从 dll 中的 IInitializableModule (Class1) 继承的 RestrictFileTypes (Class2),但它没有说明 Class2 从那时起如何替换 Class1 的所有调用,向前发展 (http://world.episerver.com/blogs/al-higgs/dates/2012/11/Restricting-the-file-types/)。你怎么看待它?
我不明白第二个要求("Moreoever...")。至于第一个,我看到了两种方式。
您可以编写class2,然后通过手动编辑交换class1 和class2 的名称。出现的次数应该很少,只有 cs 文件名和构造函数。像您通常在交换操作中所做的那样,首先使用中间名称可能会省事。这可能是最简单和最干净的方法,但您可能无法控制当前的 class1 并且无法重命名它。所以这是另一种方式。
您从头开始再次将 class2 命名为 class1,但在不同的命名空间中。您将有一个 class1 从不同命名空间中的另一个 class1(旧的)下降。完成后,在每个引用旧 class1 的文件中为新命名空间放置一个 using 指令,并确保它是最后一个 using 行,以便它优先于它上面的那些。如果当前 class1 不是引用它的同一个命名空间的成员,这应该有效。如果是后者,则必须将新名称空间的声明插入到现有名称空间的所有声明中:
namespace ns.of.old.class1
{
namespace ns.of.new.class1
{
[...]
Some reference to / use of class1
}
}
using 指令技巧很脆弱,有人可能会注意到指令不是按字母顺序排列的,然后右键单击它们,选择 "Remove and Sort"。然后您的代码可能会被破坏或更糟:仍然可以编译但再次使用旧的 class1。
我称之为 多态性 并通过继承实现,如下所示:
using System;
namespace polymorphismExample {
public class class1 {
public virtual string A => "I am Class1.A";
public string B => "I am Class1.B";
}
public class class2 : class1 {
public override string A => "I am Class2.A";
// public override string B => "I am Class1.B";
public new string B => "I am Class2.B";
}
class Program {
static void Main(string[] args) {
class1 a1_1 = new class1();
class1 b1_2 = new class2();
class2 b2_2 = new class2();
Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.A);
Console.WriteLine("{0}: {1}", "a1_1.A", a1_1.B);
Console.WriteLine();
Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.A);
Console.WriteLine("{0}: {1}", "b1_2.A", b1_2.B);
Console.WriteLine();
Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.A);
Console.WriteLine("{0}: {1}", "b2_2.A", b2_2.B);
Console.WriteLine();
Console.ReadLine();
}
}
}
输出为:
a1_1.A: I am Class1.A
a1_1.A: I am Class1.B
b1_2.A: I am Class2.A
b1_2.A: I am Class1.B
b2_2.A: I am Class2.A
b2_2.A: I am Class2.B
注意class2
中的注释行是因为不能编译;因为方法 B 在 class1
中不是虚拟的。此模式要求 class1
不是 密封的 class,并且只有 class1
中的方法被标记为 虚拟(或者当然是 abstract)将表现出所需的行为:即使在声明为 class1
类型的变量上调用时也会调用 class2
行为.
当然,在任何时候,变量都必须使用 class2
构造函数进行初始化。