C# 从泛型类型继承的数组
用于演示问题的代码:C# 从泛型类型继承的数组,c#,generics,inheritance,C#,Generics,Inheritance,用于演示问题的代码: static void Main(string[] args) { var a = new A(); var b = new B(); Base<>[] all = new Base<>[] { a, b }; // doesn't work } class Base<T> { public string Caption { get { return typeof(T).ToString(); } } }
static void Main(string[] args)
{
var a = new A();
var b = new B();
Base<>[] all = new Base<>[] { a, b }; // doesn't work
}
class Base<T>
{
public string Caption { get { return typeof(T).ToString(); } }
}
class A : Base<A> { }
class B : Base<B> { }
C#中没有类型
——您必须始终指定具体的泛型类型
唯一的解决方法是使Base
继承一个非泛型基类,或者实现一个非泛型接口。然后可以将其用作数组的类型
编辑:
在您的例子中,这非常简单,因为您想要的接口部分不包括泛型类型参数。因此,您可以简单地执行以下任一操作:
public abstract class Superbase
{
public abstract string Caption { get; }
}
public class Base<T>: Superbase
{
public override string Caption { get { return typeof(T).Name; } }
}
公共抽象类超基
{
公共抽象字符串标题{get;}
}
公共类基:超级基
{
公共重写字符串标题{get{return typeof(T).Name;}}
}
或者,使用接口:
public interface IBase
{
string Caption { get; }
}
public class Base<T>: IBase
{
public string Caption { get { return typeof(T).Name; } }
}
公共接口IBase
{
字符串标题{get;}
}
公共类基:IBase
{
公共字符串标题{get{return typeof(T).Name;}}
}
然后,您的阵列将分别是Superbase[]
或IBase[]
。在这两种情况下,您可以看到我实际上并没有提供实现——从某种意义上说,这两种声明都是“抽象的”
一般来说,我试图将非泛型内容保存在非泛型基类中,而不是将其填充到派生泛型类中。感觉更干净:)基于@Luaan idea,下面是一个实现:
class Program
{
static void Main(string[] args)
{
var a = new A();
var b = new B();
var arr = new Base[] { a, b};
foreach (var obj in arr)
Console.WriteLine(obj.Caption);
Console.ReadKey();
}
}
public class Base<T> : Base
{
public override string Caption
{
get { return typeof (T).ToString(); }
}
}
public class A : Base<A> { }
public class B : Base<B> { }
public abstract class Base
{
public abstract string Caption { get; }
}
类程序
{
静态void Main(字符串[]参数)
{
var a=新的a();
var b=新的b();
var arr=新碱基[]{a,b};
foreach(arr中的var obj)
控制台写入线(对象标题);
Console.ReadKey();
}
}
公共类基:基
{
公共重写字符串标题
{
获取{return typeof(T).ToString();}
}
}
公共类A:基{}
公共类B:基{}
公共抽象类基
{
公共抽象字符串标题{get;}
}
不要尝试使用继承(这将导致更多问题),而是使用扩展方法:
public interface IClassAORClassB {}
class A : IClassAORClassB { }
class B : IClassAORClassB { }
public static class Captions
{
public static string Caption<T>(this T obj) where T : IClassAORClassB
{
return obj.GetType().ToString();
}
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
var all = new IClassAORClassB[] { a, b }; // works just fine
Console.WriteLine(all[0].Caption()); // prints A
Console.WriteLine(all[1].Caption()); // prints B
}
公共接口IClassAORClassB{}
A类:IClassAORClassB{}
B类:IClassAORClassB{}
公共静态类标题
{
公共静态字符串标题(此T obj),其中T:IClassAORClassB
{
返回obj.GetType().ToString();
}
}
静态void Main(字符串[]参数)
{
var a=新的a();
var b=新的b();
var all=newiclassaorcassb[]{a,b};//工作正常
Console.WriteLine(全部[0].Caption());//打印
Console.WriteLine(全部[1].Caption());//打印B
}
您希望得到什么?它们应该实现相同的接口或基类才能工作,但.NET/CLR/C#没有。泛型在运行时创建一个新类型。为泛型类指定一个非泛型基类并创建该类型的数组。@DanielA.White不,这是一个常见的误解。与Java不同,C#泛型是一流的公民——这就是为什么事实上这是不可能的。没有通用的Base
类型可以同时容纳Base
和Base
。据我所知,唯一可以使用Base
的地方是typeof(Base)
。具体泛型类的类型必须在编译时知道(当然不包括反射)。我希望从all
获得Caption
,但不知道如何获得。这应该是非常容易的,或者完全不可能的。如果是后一种情况,那么我希望看到我的问题的解决方案-将标题
移动到一个基类中,每个类型的标题都会以某种方式得到解决。@Sinatr消除了歧义。之前我发现了这一点,但对我帮助不大。您是否应该知道非泛型基类的Caption
可访问性到底是什么样的?我知道我的代码不起作用,但在当前的形式下,答案对我并没有帮助。接口解决方案让我感到非常愚蠢。我真的很笨。谢谢。事实上,虽然我考虑过使用扩展方法,但在这种情况下它并没有帮助——如果您想在all
的元素上使用它,就不会有帮助。它使用本地的编译时类型,而不是运行时,这在这里是不合适的。更不用说OP需要一个特定的类型参数,而不是继承类的类型。@Luaan,你是说typeof(T).ToString()
将始终返回IClassAORClassB
?这是一个有趣的想法,谢谢,但正如@Luaan所评论的,all[0]。Caption()
不会达到预期效果。或者它会吗?对于所有[a]
和所有[b]
,它将返回IClassAORClassB
,对于a
和b
返回a
。有用,但不是OP想要的。@Luaan,你是对的。我已将代码修改为使用obj.GetType()
而不是typeof
。现在它可以正常工作了。
public interface IClassAORClassB {}
class A : IClassAORClassB { }
class B : IClassAORClassB { }
public static class Captions
{
public static string Caption<T>(this T obj) where T : IClassAORClassB
{
return obj.GetType().ToString();
}
}
static void Main(string[] args)
{
var a = new A();
var b = new B();
var all = new IClassAORClassB[] { a, b }; // works just fine
Console.WriteLine(all[0].Caption()); // prints A
Console.WriteLine(all[1].Caption()); // prints B
}