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
}