如何将方法隐藏(新)与通用约束类一起使用
-
27-09-2019 - |
题
我有一个容器类,它有一个通用参数,该参数仅限于某个基类。提供给泛型的类型是基类约束的子类型。子类使用方法隐藏(新)来更改基类中方法的行为(不,我不能将其设为虚拟,因为它不是我的代码)。我的问题是,“新”方法没有被调用,编译器似乎认为提供的类型是基类,而不是子类,就好像我已将其向上转型为基类一样。
显然我在这里误解了一些基本的东西。我以为通用的 where T: xxx
是一个约束,而不是向上转换类型。
这个示例代码基本上演示了我正在谈论的内容。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace GenericPartialTest
{
class ContextBase
{
public string GetValue()
{
return "I am Context Base: " + this.GetType().Name;
}
public string GetOtherValue()
{
return "I am Context Base: " + this.GetType().Name;
}
}
partial class ContextSub : ContextBase
{
public new string GetValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
partial class ContextSub
{
public new string GetOtherValue()
{
return "I am Context Sub: " + this.GetType().Name;
}
}
class Container<T> where T: ContextBase, new()
{
private T _context = new T();
public string GetValue()
{
return this._context.GetValue();
}
public string GetOtherValue()
{
return this._context.GetOtherValue();
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Simple");
ContextBase myBase = new ContextBase();
ContextSub mySub = new ContextSub();
Console.WriteLine(myBase.GetValue());
Console.WriteLine(myBase.GetOtherValue());
Console.WriteLine(mySub.GetValue());
Console.WriteLine(mySub.GetOtherValue());
Console.WriteLine("Generic Container");
Container<ContextBase> myContainerBase = new Container<ContextBase>();
Container<ContextSub> myContainerSub = new Container<ContextSub>();
Console.WriteLine(myContainerBase.GetValue());
Console.WriteLine(myContainerBase.GetOtherValue());
Console.WriteLine(myContainerSub.GetValue());
Console.WriteLine(myContainerSub.GetOtherValue());
Console.ReadKey();
}
}
}
编辑:
我想我的困惑来自于人们可以做到这一点
class SomeClass<T> where T: AnotherType, new()
{
T foo = new T();
}
我期望 T
成为 T
即使我了解编译器会查看 T
作为有 AnotherType
的界面。我假设输入的是 T
即使接口 T
在编译时设置。这 T foo
声明在这里似乎具有误导性,因为它确实在做
AnotherType foo = new T();
当我明白这并不是真正的宣告 foo
作为类型 T
, ,这是可以理解的,为什么 new
方法隐藏不起作用。
这就是我要说的。
解决方案
声明的方法 new
(从编译器的角度来看)与基类中具有相同名称/签名的方法没有关系。 这只是编译器允许您在派生类中定义不同方法的方式,这些方法与其基类层次结构中的方法共享签名。
现在,根据您的具体情况,请意识到泛型必须编译为一组字节码,无论作为泛型参数提供的类型如何. 。因此,编译器只知道在泛型类型 T 上定义的方法和属性 - 这将是您在泛型约束中指定的基类型。编译器对以下内容一无所知 new
派生类型中的方法,即使您使用派生类型作为参数创建泛型类型的实例。因此,泛型类中的调用将始终转到基类型的方法。
关于 new/virtual/override 有很多混淆; 采取一个 看看这个问题 - 杰森和埃里克的回答非常好。 乔恩·斯基特的回答 类似的问题也可以帮助您理解为什么您的实现会如此运行。
您可以通过两种方法来解决此问题:
- 执行条件转换 (基于运行时类型信息)到泛型类中的派生类型(或接口)。这会破坏封装并增加不需要的耦合。如果实施不当,它也很脆弱。
- 定义一个接口 您在通用约束中使用它来公开您关心的方法。如果您无法更改派生的代码,则这可能是不可能的。
其他提示
我觉得这太问题我问可以帮助你。见乔恩斯基特的回答有它为什么是不可能的。
添加其他层 - 继承你一般不会从您的第三方类,但来自一类新的从第三方转继承。在这个新的类,你可以定义的问题作为新的虚拟方法。如果你所有的代码永远不会直接引用的第三部分类,它应该工作