![](/img/trans.png)
[英]How do I register generic Action or Command handlers and then call the right one when the type is determined at runtime?
[英]How do I create a generic property where the type is determined by the compiler?
我已经搜索过,但找不到我需要做的答案。 我需要有两个从基类继承的类,具有通用属性。 属性的类型应由编译器确定,具体取决于类的类型。 现在,我有这个:
public abstract class AbstractClass<T>
{
public abstract List<T> Items { get; set; }
}
public class ChildClass1 : AbstractClass<MyType1>
{
public override List<MyType1> Items { get; set; }
}
public class ChildClass2 : AbstractClass<MyType2>
{
public override List<MyType2> Items { get; set; }
}
但是在创建新的AbstractClass对象时,我仍然必须指定所需的类型:
AbstractClass<MyType1> child1 = new ChildClass1();
我该怎么做,以使我在创建实例时不必指定属性的类型?
例如:
AbstractClass child1 = new ChildClass1();
让您的AbstractClass<T>
已经从一个更通用的AbstractClass
继承,您在这里在编译时不知道类型T的情况下工作。 在那里您可以使用完全不依赖T的通用方法。 此时,您将无法直接访问基于T的任何项目。
public abstract class AbstractClass
{
public abstract void MethodOnAbstractClass();
}
public abstract class AbstractClass<T>: AbstractClass
{
public abstract List<T> Items { get; set; }
}
但是,您已经可以定义抽象方法,这些方法将在可能依赖于T的信息的特殊类中实现,如下所示:
public abstract class AbstractClass
{
public abstract IList GetItems(); //has to be implemented later on
}
public abstract class AbstractClass<T>: AbstractClass
{
public List<T> Items { get; set; }
public override IList GetItems() { return Items; } //Items only visible as objects.
public AbstractClass()
{
Items = new List<T>(); //Make sure example further down is working.
}
}
class ChildClass1 : AbstractClass<MyType1> { }
class ChildClass2 : AbstractClass<MyType2> { }
此处的缺点是,与Items属性相比,您将不知道编译时(但仅在运行时)返回的GetItems()的IList中包含的类型。 但是它允许您执行以下操作:
AbstractClass child;
child = new ChildClass1();
int count1 = child.GetItems().Count;
child = new ChildClass2();
int count2 = child.GetItems().Count;
好的,正如您所发现的,您不能这样做。
但为什么?
因为AbstractClass
不是类型,所以AbstractClass<string>
是类型。 “为什么?” 这就是“因为这就是它的工作方式”。
您必须在某个阶段告诉编译器哪种类型正在替换T
声明对类的引用时,必须先完成定义类的方法。
您可以尝试其他方法,但是如果不指定类型就永远无法使用该属性(除非您要完全删除类型安全性并且到处都有object
,但是我认为没有人会建议这样做!)
您可以声明一个接口
interface GenericItems
{
T GetItems<T>();
}
并具有实现该目标的AbstractBaseClass
,但是没有什么可以阻止某人要求与实现该对象的类型T
不同的类型的,所以实际上这也不是解决方案
最好的方法是设计它的方法,它只能这样工作,因为编译器需要知道您实际需要哪种类型的AbstractClass。 它无法从作业的右侧进行推断。
但是,如果你想多态治疗各种抽象类的对象,你不关心类型的Items
属性,当你做到这一点,那么你可以创建一个AbstractBaseClass
不是一个泛型类型。 您将所有多态位放在“ AbstractBaseClass”中,然后让AbstractClass<T>
从AbstractBaseClass继承。
例如
abstract class AbstractBaseClass
{
abstract void DoThis();
abstract void DoThat();
}
abstract class AbstractClass<T>
: AbstractBaseClass
{
override void DoThis(){...}
override void DoThat(){...}
public T Items{...}
}
那你可以做
AbstractBaseClass abstractBaseClass = new ChildClass1();
abstractBaseClass.DoThis();
不过你不能这样做
AbstractBaseClass abstractBaseClass = new ChildClass1();
abstractBaseClass.Items.Count; // Compiler error, unknown property or method Items
以这个基类为例:
public abstract class Base<T>
{
public abstract List<T> TheList { get; set; }
}
您可以开设儿童班:
public class MyClass : Base<string>
{
public override List<string> TheList
{
get { throw new NotImplementedException(); }
set { throw new NotImplementedException(); }
}
}
您的子属性仍然需要指定属性类型。 您必须明确,不能使用var
东西。
编译器无法告诉您要使用通用参数作为属性的类型。 如果您使用的是Visual Studio,并且有一个空白的子类,它将对您有所帮助,但是最终该语言仍将要求您提供每个属性的类型。
这将创建您在上面看到的MyClass代码。
实例化该类时,不必提供通用参数,因为您已经知道MyClass
会将string
作为通用参数传递给Base
。
var mc = new MyClass();
//mc is a MyClass, which inherits from Base<string>
但是再次,您必须提前告诉班级什么是什么类型。
但是,如果您不想创建子类,则可以直接使用基类。 从基类中删除“摘要”后,请使用:
var b1 = new Base<string>;
List<string> b1List = b1.TheList; //TheList is now a string list
是的,创建新对象时必须设置类型,但是不必创建子类。
无论哪种方式,您都必须在某个地方定义类型。 是否要在子类或对象实例中完成取决于您。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.