有没有一种解决方法不能够推断使用类型约束泛型类型参数的C#? [英] Is there a workaround to C# not being able to infer generic type arguments using type constraints?

查看:319
本文介绍了有没有一种解决方法不能够推断使用类型约束泛型类型参数的C#?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



埃里克利珀在他的博客文章在的 http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of -the-signature.aspx 约束为什么不考虑类型推断,这是有道理的因为方法无法通过简单地改变类型的限制超载。不过,我想找到一种方法来实例化使用两个泛型类型,其中一个可以推断,另外,如果限制被认为这可以推断,一个对象,而无需指定任何的类型。



由于类型:



<预类=郎-CS prettyprint-覆盖> 公共接口I< T>
{
&其他LT; T> CreateOther();
}

公共类C:I<串GT;
{
公共其他与LT;字符串> CreateOther()
{
返回新其它<串GT;();
}
}

公共类其它< T>
{
}

和工厂:



<预类=郎-CS prettyprint-覆盖> 公共静态类FACTORY1
{
公共静态元组LT; T,其它< T1>>创建< T,T1>(T O)其中T:I< T1>
{
返回新的记录< T,其它< T1>>(邻,o.CreateOther());
}
}



以下所需的代码将不能编译:



<预类=郎-CS prettyprint-覆盖> 公共无效WontCompile()
{
C C =新C();
变种V = Factory1.Create(三); //将无法编译
}



错误消息是错误CS0411:类型对于法yo.Factory1.Create(T)参数不能从使用推断。尝试显式指定类型参数。,这是什么埃里克在他的博客中说行。



因此,我们可以简单明确地指定泛型类型参数,作为错误信息显示:



<预类=郎-CS prettyprint-覆盖> 公共无效SpecifyAllTypes()
{
C C =新C();
变种V = Factory1.Create< C,串>(C); //类型是元组&所述℃,其它与所述;串GT;>
}

如果我们不希望指定类型的参数,我们不需要留住C型,我们可以使用下面的工厂:



<预类=郎-CS prettyprint-覆盖> 公共静态类FACTORY2
{
公共静态元组LT; I< T1>中其它< T1>> CreateUntyped< T1>(I< T1≠0)
{
返回新的记录< I< T1>中其它< T1>>(邻,o.CreateOther());
}
}

和现在指定:



<预类=郎-CS prettyprint-覆盖> 公共无效非类型化()
{
C C =新C();
变种V = Factory2.CreateUntyped(三); //类型是元组LT; I<串>中其它<串GT;>
}



不过,我希望保留在返回的对象类型C和未指定类型。


我想出了一个解决这个问题
解决方案


,但它似乎是。一个杂牌一种变通方法,其中C类对象是一个两步工厂调用中使用两次



要做到这一点,下面的工厂用于:



<预类=郎-CS prettyprint-覆盖> 公共静态类Factory3
{
公共静态工厂< T1> CreateFactory< T1>(I< T1≠0)
{
返回新工厂和LT; T1>();
}
}

公共类工厂< T1>
{
公开元组LT; T,其它< T1>>创建< T>(T O)其中T:I< T1>
{
返回新的记录< T,其它< T1>>(邻,o.CreateOther());
}
}



然后可使用如下:

<预类=郎-CS prettyprint-覆盖> 公共无效推断()
{
C C =新C();
变种V = Factory3.CreateFactory(三).Create(三); //类型是元组&所述℃,其它与所述;串GT;>
}



这是由于C使用了两次这只是感觉奇怪。因为它只是被用来推断基本类型参​​数是用它的第一次实际上是被丢弃。



有没有更好的办法解决这个问题,其中对象呢?并不需要使用两次和类型不需要指定



编辑:我才意识到,虽然对象必须是用过两次,不需要第二工厂类。相反,这两个参数可能只是在同一个工厂方法使用方法如下:



<预类=郎-CS prettyprint-覆盖> 公共类厂
{
公开元组LT; T,其它< T1>>创建< T,T1>(T O,I< T1> O2)其中T:I< T1>
{
返回新的记录< T,其它< T1>>(邻,o.CreateOther());
}
}

这将用于如下:



<预类=郎-CS prettyprint-覆盖> 公共无效推断()
{
C C =新C();
变种V = Factory.Create(C,C); //类型是元组&所述℃,其它与所述;串GT;>
}



它仍然不理想,但不必创建第二个工厂类更好,和至少可用于xmlDoc中注释,指示这两个参数应该是相同的对象。再次,一个参数( O2 在这种情况下)仅用于推断约束类型 T


Eric Lippert has explained in his blog post at http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx why constraints are not considered for type inference, which makes sense given that methods cannot be overloaded by simply changing type constraints. However, I would like to find a way to instantiate an object using two generic types, one which can be inferred and another which could be inferred if constraints were considered, without having to specify any of the types.

Given the types:

public interface I<T>
{
    Other<T> CreateOther();
}

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

public class Other<T>
{
}

and the factory:

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());
    }
}

the following desired code will not compile:

    public void WontCompile()
    {
        C c = new C();
        var v = Factory1.Create(c); // won't compile
    }

The error message is "error CS0411: The type arguments for method 'yo.Factory1.Create(T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.", which is in line with what Eric said in his blog post.

Thus, we can simply specify the generic type arguments explicitly, as the error message suggests:

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

If we don't wish to specify type arguments and we don't need to retain type C, we can use the following factory:

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());
    }
}

and now specify:

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

However, I wish to retain type C in the returned object and not specify the types.

解决方案

I came up with a solution to this problem, but it seems to be a kludge of a workaround, where the object of type C is used twice in a two-step factory call.

To do this, the following factories are used:

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());
    }
}

which can then be used as follows:

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

This just feels odd since c is used twice. The first time it is used it is actually discarded as it is just being used to infer the base type argument.

Is there a better solution to this problem where the object does not need to be used twice and the types do not need to be specified?

edit: I just realized that, although the object must be used twice, the second factory class is not needed. Rather, both parameters could just be used in the same factory method as follows:

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());
    }
}

This would be used as follows:

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

It's still not ideal, but better than having to create a second factory class, and at least XMLDoc comments could be used to indicate that both parameters should be the same object. Once again, the one parameter (o2 in this case) is only used to infer the constrained types for T.

这篇关于有没有一种解决方法不能够推断使用类型约束泛型类型参数的C#?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆