C#无法使用类型约束推断泛型类型参数,是否有解决方法?

10
Eric Lippert在他的博客文章http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx中解释了为什么类型约束不被考虑在类型推断中,这是有道理的,因为方法不能通过简单地改变类型约束来进行重载。然而,我想找到一种使用两个泛型类型实例化对象的方法,其中一个可以被推断,另一个如果考虑约束就可以被推断,而无需指定任何类型。
给定以下类型:
public interface I<T>
{
    Other<T> CreateOther();
}

public class C : I<string>
{
    public Other<string> CreateOther()
    {
        return new Other<string>();
    }
}

public class Other<T>
{
}

和工厂:

public static class Factory1
{
    public static Tuple<T, Other<T1>> Create<T, T1>(T o) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

以下期望的代码将无法编译:
    public void WontCompile()
    {
        C c = new C();
        var v = Factory1.Create(c); // won't compile
    }

错误信息是“error CS0411:无法从使用中推断方法'yo.Factory1.Create(T)'的类型参数。尝试显式指定类型参数。”,这与Eric在他的博客文章中说的一致。
因此,我们可以简单地按照错误信息建议显式指定泛型类型参数:
    public void SpecifyAllTypes()
    {
        C c = new C();
        var v = Factory1.Create<C, string>(c); // type is Tuple<C, Other<string>>
    }

如果我们不想指定类型参数并且不需要保留类型C,我们可以使用以下工厂:
public static class Factory2
{
    public static Tuple<I<T1>, Other<T1>> CreateUntyped<T1>(I<T1> o)
    {
        return new Tuple<I<T1>, Other<T1>>(o, o.CreateOther());
    }
}

现在指定:

    public void Untyped()
    {
        C c = new C();
        var v = Factory2.CreateUntyped(c); // type is Tuple<I<string>, Other<string>>
    }

然而,我希望在返回的对象中保留类型C,而不指定类型。
1个回答

5
我想到了一个解决这个问题的方法,但似乎是一个折衷的解决方案,其中类型为C的对象在两步工厂调用中被使用了两次。
为此,使用以下工厂:
public static class Factory3
{
    public static Factory<T1> CreateFactory<T1>(I<T1> o)
    {
        return new Factory<T1>();
    }
}

public class Factory<T1>
{
    public Tuple<T, Other<T1>> Create<T>(T o) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

然后可以按如下方式使用:

    public void Inferred()
    {
        C c = new C();
        var v = Factory3.CreateFactory(c).Create(c); // type is Tuple<C, Other<string>>
    }

这感觉有些奇怪,因为c被使用了两次。第一次使用时,它实际上被丢弃了,因为它只是用来推断基本类型参数的。
有没有更好的解决方案,使对象不需要被使用两次,而且不需要指定类型?
编辑:我刚意识到,尽管对象必须被使用两次,但第二个工厂类并不需要。相反,两个参数可以在同一个工厂方法中使用,如下所示:
public class Factory
{
    public Tuple<T, Other<T1>> Create<T, T1>(T o, I<T1> o2) where T : I<T1>
    {
        return new Tuple<T, Other<T1>>(o, o.CreateOther());
    }
}

这将如下使用:
public void Inferred()
{
    C c = new C();
    var v = Factory.Create(c, c); // type is Tuple<C, Other<string>>
}

这仍然不是最理想的解决方案,但比创建第二个工厂类要好一些,至少可以使用XMLDoc注释来指示两个参数应该是相同的对象。再次强调,这里只使用一个参数(在本例中为o2)来推断T的受限类型。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接