C#中的泛型继承?
可能重复:C#中的泛型继承?,c#,generics,inheritance,C#,Generics,Inheritance,可能重复: 我能行 public class MyGenericClass : DL //but i cannot do public class MyGenericClass <T> : T 公共类MyGenericClass:DL //但我做不到 公共类MyGenericClass:T 第二步我该怎么做?如果我做不到,我怎么能做这样的事情呢 public class MyGenericClass <T> { T obj; //have all
我能行
public class MyGenericClass : DL
//but i cannot do
public class MyGenericClass <T> : T
公共类MyGenericClass:DL
//但我做不到
公共类MyGenericClass:T
第二步我该怎么做?如果我做不到,我怎么能做这样的事情呢
public class MyGenericClass <T>
{
T obj;
//have all MyGenericClass.XYZ call obj.XYZ
}
public interface IXyzable { void xyz(); }
public class MyGenericClass<T> : IXyzable where T : IXyzable {
T obj;
public void xyz() {
obj.xyz();
}
}
公共类MyGenericClass
{
T-obj;
//让所有MyGenericClass.XYZ调用obj.XYZ
}
这是不可能的,因为根据T的类型,MyGenericClass的公共接口会发生变化
如果有许多不同的类都公开同一个接口,那么可以声明MyGenericClass来公开该接口,并且在所有函数的实现中,将调用委托给obj
public class MyGenericClass <T>
{
T obj;
//have all MyGenericClass.XYZ call obj.XYZ
}
public interface IXyzable { void xyz(); }
public class MyGenericClass<T> : IXyzable where T : IXyzable {
T obj;
public void xyz() {
obj.xyz();
}
}
公共接口IXyzable{void xyz();}
公共类MyGenericClass:IXyzable其中T:IXyzable{
T-obj;
公共void xyz(){
obj.xyz();
}
}
编辑:现在我理解了这个问题您将需要所有可能的T来实现一些接口,以便您知道obj.XYZ()是有意义的,然后您就可以这样做了
public interface Ixyz
{
void XYZ();
}
public class MyGenericClass<T> : Ixyz where T:Ixyz, new()
{
T obj;
public MyGenericClass()
{
obj = new T();
}
public void XYZ()
{
obj.XYZ();
}
}
公共接口Ixyz
{
void XYZ();
}
公共类MyGenericClass:Ixyz,其中T:Ixyz,new()
{
T-obj;
公共MyGenericClass()
{
obj=新的T();
}
公共void XYZ()
{
obj.XYZ();
}
}
我也让MyGenericClass实现了Ixyz,因为它显然公开了正确的方法,但这可能是最好的选择,因为它允许
var x = new MyGenericClass<MyGenericClass<SomeClass>>();
var x=新的MyGenericClass();
这不太可能是一个好主意。这几乎是duck类型,但您可以使用反射。 当您使用对obj的引用创建泛型类时,请使用反射来尝试找到具有正确签名的方法。只要存储对该方法的引用,性能就不会太差
class BaseGeneric<T>
{
private T obj;
private MethodInfo mi;
private const string MethodNameOfInterest = "Xyz";
public BaseGeneric(T theObject)
{
this.obj = theObject;
Type t = obj.GetType();
mi = t.GetMethod(MethodNameOfInterest);
}
public void Xyz()
{
mi.Invoke(obj, null);
}
}
classbasegeneric
{
私人T obj;
私有方法信息mi;
private const string MethodNameOfInterest=“Xyz”;
公共基泛型(T对象)
{
this.obj=对象;
类型t=obj.GetType();
mi=t.GetMethod(MethodNameOfInterest);
}
公共void Xyz()
{
mi.Invoke(obj,null);
}
}
当然,您需要为错误检查等添加更多内容,但这就是您可以做的要点。另外,不要忘记将System.Reflection命名空间添加到using子句。类型系统将不允许您尝试的表单的类型声明。不允许这样做的一个原因应该是直观的:当
T
是密封类(例如System.String
)时,MyGenericClass
将如何操作
如果您确实需要此功能(并且您知道将要使用的类型
T
未密封),则可以在运行时使用Reflection.Emit
命名空间中的类生成代理。使用诸如PostSharp之类的AOP工具也可以达到这种效果。具体问题是,为什么不能这样做:
public class MyGenericClass<T> : T
但是对于继承版本,这个技巧不起作用
此外,许多有用的设施不可能通过接口约束来描述。当您从类型继承时,您可以做的不仅仅是对其调用方法,还可以重写它们。考虑这个假设的例子:
class MyBase
{
public virtual void MyVirtual() { }
}
class MyGenericDerived<T> : T
{
public override void MyVirtual()
{
Console.WriteLine("Overridden!");
}
}
MyBase obj = new MyGenericDerived<MyBase>();
obj.MyVirtual();
类MyBase
{
公共虚拟空间MyVirtual(){}
}
类MyGenericDerived:T
{
公共覆盖无效MyVirtual()
{
Console.WriteLine(“重写!”);
}
}
MyBase obj=新的MyGenericDerived();
obj.MyVirtual();
我想做的是类似于“mix-in”的事情,其中MyGenericDevertive提供了虚拟函数的定义,无论它应用于什么基础。但是编译器如何知道T将有一个名为MyVirtual的方法可以被重写呢?我需要在T上加一个约束。我如何通过接口来表达它?这是不可能的。一旦允许从类型参数继承,使用接口来描述约束就不是一个合适的解决方案。这就是为什么它在今天的语言中不存在的另一个原因。这是怎么回事:
class BaseClass<T>
{
public T property { get; set; }
}
class GenericClass<T> : BaseClass<T>
{
}
class Program
{
static void Main(string[] args)
{
GenericClass<int> l = new GenericClass<int>();
l.property = 10;
}
}
类基类
{
公共T属性{get;set;}
}
类GenericClass:基类
{
}
班级计划
{
静态void Main(字符串[]参数)
{
GenericClass l=新的GenericClass();
l、 财产=10;
}
}
这实现了您想要做的事情?为什么要投反对票?我回答了这个问题,不是吗?我不建议这样做,但它确实解决了他的问题:BaseGeneric.Xyz()调用底层对象的Xyz()方法,而不管该方法是什么类型。您的解决方案具有反射的所有缺点,并且没有duck类型的好处。外部对象(BaseGeneric)上必须声明所有函数。如果您知道这些函数,只需调用相同的函数即可?它缓存MethodInfo,因此性能损失会降低。它看起来像底层对象,所以它会嘎嘎作响。这确实让他重新实现了每种方法,所以这是最大的缺点。但是,T可以是实现Xyz的任何东西,在某些场景中很方便。如果您让他手动实现该方法,那么为什么不直接调用实现方法呢?为什么要使用反射呢?那是向下的声音的来源是的,你是对的。我感谢你的解释。我的方法唯一的优点是T可以是任何具有方法Xyz的类。如果无法访问代码且无法使用接口,则此操作非常方便。使用非常有限,但与C#4.0中即将出现的动态类型类似。您尝试这样做的动机是什么?等待C#4.0中的动态类型。但在第二种情况下,T用于声明成员,该成员可能是公共的,然后MyGenericClass的公共接口将根据T的类型而改变。只是属性的数据类型,它本质上由.net和泛型处理。我的观点更倾向于t