推断C#通用类型的子类

时间:2011-02-04 15:12:26

标签: c# generics

我有一个泛型类Proxy<T>,我想编写另一个泛型类,其类型参数是代理。

我想写:

public class MyClass<U> where U : Proxy<T>

但编译器会报告The type or namespace name T could not be found

我发现的一个解决方案就是声明它:

public class MyClass<U, T> where U : Proxy<T>

但这似乎很笨拙,因为客户端必须声明两个类型参数,如:

public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass> { ... }

然后在某个客户端:

var proxyWrapper = new MyClass<SomeProxy, SomeClass>();

如何在MyClass上无需两个泛型类型的情况下执行此操作。毕竟,如果我们知道第一个是SomeProxy,则应该遵循第二个SomeClass

6 个答案:

答案 0 :(得分:2)

也许这样的事情也可以完成这项工作?

class Test<T> {
    public Test(Proxy<T> proxy) { this.MyProxy = proxy; }
    public Proxy<T> MyProxy { get; private set; }
}

答案 1 :(得分:1)

您可以拥有一个接口IMyClass<SomeProxy>和一个工厂方法,用于创建并返回MyClass<SomeProxy, SomeClass>的实例。您可能需要使用Reflection创建实例。

我有类似情况的代码示例here:最终用户只关心单个类型参数,但实现需要有两个。在我的示例中,我不必使用Reflection来创建实例,但听起来您可能需要这样做。

您正在尝试使用C ++模板等编译时构造,而不是C#泛型等运行时构造。

答案 2 :(得分:1)

抱歉,如果两种类型都没有MyClass泛型,你就无法在C#中执行此操作(除非您想使用反射来创建它的实例。)

答案 3 :(得分:0)

如果您希望T在Myclass中保持通用,那么MyClass实例仍然需要解析所有内部使用的泛型类型,并且您必须在某处声明它。要走的路是你提到的冗长方式:

public class MyClass<U, T> where U : Proxy<T>

如果您不关心T中的泛型类型MyClass,请创建界面并改为使用它:

public interface IProxy { ... }
public class SomeClass { ... }
public class SomeProxy : Proxy<SomeClass>, IProxy { ... }
public class MyClass<U> where U : IProxy

然后在某个客户端:

var proxyWrapper = new MyClass<SomeProxy>();

但请注意,您不能在接口声明中使用类型T,而类型U现在更加通用。

答案 4 :(得分:0)

事实证明,我想要处理的所有SomeProxy类实际上只是覆盖了一个具有签名的Proxy<T>方法:

 T LoadInternal(Identifier id)

所以,我所做的是在MyClass中创建了一个内部类,它的构造函数中包含Func<Identifier, T>。然后我可以将Func<Identifier, T>作为参数传递给MyClass的构造函数,并使用我的子类代替SomeProxy。

似乎有点令人费解,但它对我有用。总而言之,我现在有:

public class MyClass<T>{
    private SomeProxy theProxy;

    public MyClass(Func<Identifier, T> loadDelegate){
        theProxy = new SomeProxy(loadDelegate);
    }

    /* Other methods here */

    class SomeProxy : Proxy<T>{
        private Func<Identifier, T> m_loadInternal;

        public SomeProxy(Func<Identifier, T> loadInternal){
            m_loadInternal = loadInternal;
        }

        protected override T LoadInternal(Identifier id){
            return m_loadInternal(id);
        }
    }
}

因此,从客户端代码开始,我只使用以下方法创建MyClass,而不是编写一个扩展Proxy然后覆盖该类的LoadInternal的类。

var myClass = new MyClass<T>(x => CodeWhichReturnsT());

答案 5 :(得分:0)

  

如何在MyClass上不必拥有两个泛型类型的情况下执行此操作。毕竟,如果我们知道第一个是SomeProxy,那么应该遵循第二个是SomeClass。

虽然你似乎找到了问题主要部分的答案,但我想我会提供对这一部分的理解。听起来你希望你能做到这样的事情:

class Proxy<T> 
{ 
    T Value { get; set; }
}
class MyClass<U> where U : Proxy<> { }

并在您提供Proxy时让编译器填写U类型参数。由于您已声明U继承自Proxy,因此您必须打算使用Proxy上的一个方法,这可能使用T参数,如下所示:

class MyClass<U> where U : Proxy<>
{
    void SomeMethod(U parameter)
    {
        var local = parameter.Value;
        //more code here...
    }
}

现在,编译器应该在这里为local推断出什么?这是我看到的主要问题,如果可能的话,很难实现这样的功能。如果您不想使用任何使用泛型类型的Proxy的方法,您可以改为创建非泛型基类并将其用于U并回避整个问题。

我不是编译器编写者,但想到如何解决这个问题的几种可能性。它可以说对象(或者你在代理中对类型参数施加的任何其他限制),但这似乎不太正确或者正常的泛型似乎做的事情。这也需要CLR允许打开泛型类型作为泛型参数的约束,我怀疑它是否存在。我能看到的另一个选项是类型实际上有第二个类型参数,编译器为你提供语法糖,使其更容易。

无论你走到哪里,这个功能似乎都可以在很少的情况下获得一些好处,因此不太可能实现切割。