在C#Generics中这是不可能的?

时间:2016-09-21 02:26:01

标签: c# generics

class Bar
{
    static public Bar Instance { get { return null; /*return instance*/ } }
}

private void Foo<T>() where T : Bar
{
    T getInstace = T.Instance;
}

这是错误,但需要获取实例。

这有解决方案吗?

感谢

++

class Bar<T>
{
    static public T Instance { get { return default(T); /*return instance*/ } }
}

class BarChild : Bar<BarChild>
{ 
    public void Func(){}
}

private T Foo<T>() where T : Bar<T>
{
    return T.Instance;
}

private void Example()
{
    Foo<BarChild>().Func();
}

我想这样做,你知道。 但是,“T.Instance”是错误的..

2 个答案:

答案 0 :(得分:0)

我认为这归结为对static关键字的基本误解。它不是跨实例共享成员的机制,它是一种通知编译器它可以静态分配成员的方法,即不考虑程序在运行时的动态行为。

请注意,您无法成为static成员virtual,这意味着您无法在子类中覆盖它。由于子类化是一个静态过程,因此您可以引用父类的静态成员,就像它们被继承一样,因为编译器可以确定成员的定义位置。

即使您所描述的内容在语法上是合法的,T.Instance也无法引用Bar.Instance以外的任何内容。

答案 1 :(得分:0)

你实际上已经接近做你想做的事了。有些人可能认为这是滥用类型系统。我认为这是语言的弱点。您要解决的问题是您要访问泛型类的静态成员,该类的类型是类的类型,而不是硬编码类型。 可能。

class Base<T> where T : Base<T> {
    public static T SomeMethod() { ... }
}

class Derived : Base<Derived> {

}

public void Main() {
    Derived d = Derived.SomeMethod();  // correctly returns an object of type Derived, even though method is defined in base class
}

这是来自C ++的CRTP的变体。

所以这不是真正的虚拟或动态调度。使用静态函数获得此行为的唯一原因是泛型。这些类型在编译时都是已知的。它在类层次结构中仍然有用,在这种层次结构中,您希望派生类型能够使用基类型方法,就好像它们是派生类型的方法一样。或者,换句话说,您可以在基类中创建在派生类中工作的模板化方法,就像在那里声明它们一样。您可能想要使用它的一个地方是Clone()方法,它返回正确的类型。您可以在基类中将其声明为public abstract T Clone(),并且它在派生类中具有正确的返回类型。

编辑:更新代码以执行OP想要的所有内容:

public class Base<T>
    where T : Base<T>, new() {
    public static T Instance {
        get {
            return new T();
        }
    }
}

public class Derived : Base<Derived> {
    public void SomeFunc() {
        Console.WriteLine("SomeFunc()");
    }
}

// in other code

private T Foo<T>() where T : Base<T>, new() {
    // note that we can't just use T directly here, but that's okay, because we know that T is always going to be at least a Base<T>
    return Base<T>.Instance;
}

private void Example() {
    // the type of Base<Derived>.Instance is Derived, so you can call Func() on it
    Base<Derived>.Instance.SomeFunc();

    // can also do this:
    Foo<Derived>().SomeFunc();
}