使用多个泛型类型参数进行类型推断 [英] Type inference with multiple generic type parameters

查看:96
本文介绍了使用多个泛型类型参数进行类型推断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我不明白为什么C#在以下完整情况下不会推断出类型:

  public interface IThing { } 

public class Thing1:IThing {}

public class Thing2:IThing {}

public interface IContainer {}

public class Container1:IContainer
{
public IThing A {get {return new Thing1(); }}
public IThing B {get {return new Thing2(); }}
}

public class Container2:IContainer
{
public IThing C {get {return new Thing1(); }}
public IThing D {get {return new Thing2(); }}
}

public class SomeClass
{
public void PerformTask(){}
}

public static class ExtensionMethods
{
//这个函数表现得和我预期的一样,推断TContainer
public static TContainer DoStuffWithThings< TContainer>(这个TContainer容器,Func< TContainer,IThing> getSomething,Func< TContainer, IThing> getSomethingElse)
其中TContainer:IContainer
{
var something = getSomething.Invoke(container);
var somethingElse = getSomethingElse.Invoke(container);

//我们在lambda表达式中指定了相对于容器

return容器的东西和其他东西,
}

//所讨论的方法
public static TCustomReturnType DoStuffWithThings< TContainer,TCustomReturnType>(该TContainer容器,Func< TContainer,IThing> getSomething,Func< TContainer,IThing> ; getSomethingElse)
where TContainer:IContainer
where TCustomReturnType:new()
{
var something = getSomething.Invoke(container);
var somethingElse = getSomethingElse.Invoke(container);

//像上面那样做事情的东西

//这次我们返回自定义类型
return new TCustomReturnType();



类公共类驱动
{
public static void Main(string [] args)
{
var container1 = new Container1();
var container2 = new Container2();
//我可以为每个容器做些东西,每次都返回容器。

container1.DoStuffWithThings(c => c.A,c => c.B)
.DoStuffWithThings(c => c.B,c => c.A);

container2.DoStuffWithThings(c => c.C,c => c.D)
.DoStuffWithThings(c => c.D,c => c.C);

//现在我们试着做同样的事情,但是使用自定义返回类型
container1.DoStuffWithThings< Container1,SomeClass>(c => cA,c => cB)
.PerformTask();
//如您所见,编译器要求我们将Container1指定为容器类型。
//为什么不能推断?它从Container1的实例中调用。
//我期望的行为是针对container1.DoStuffWithThings< SomeClass>(...)推断
//容器类型并返回SomeClass的新实例。




$ b $ p
$ b

基本思想是当只有一个通用的类型参数,编译器推断类型。当我添加第二个时,编译器不会推断(它显然不能推断第二个,但我不知道为什么它不能推断第一个)。我的问题是为什么容器的类型没有被推断?

解决方案

原因是第二个类型参数没有被使用任何功能参数。因此,它是无法通过参数使用纯粹推断出的。



如果你有一个像这样的方法签名(显然不等于你的代码,只是一个例如):
$ b $ pre $ public static TResult DoStuffWithThings< TContainer,TResult>(
这个TContainer容器,
Func< ; TContainer,TResult> getSomething)

然后如果你想避免指定第一个参数,你可以把方法分成两个函数,并隐藏一个泛型类型的中间参数,比如这:

  public static IntermediateResult< T> DoStuffWithThings< T>(此T容器)

public class IntermediateResult< T>
{
Public WithReturnType< TResult>()
}

然后它调用

  var result = container.DoStuffWithThings()。WithReturnType< Result>(); 


I don't understand why C# doesn't infer a type in the following complete situation:

public interface IThing {}

public class Thing1 : IThing {}

public class Thing2 : IThing {}

public interface IContainer {}

public class Container1 : IContainer
{
    public IThing A { get { return new Thing1(); } }
    public IThing B { get { return new Thing2(); } }
}

public class Container2 : IContainer
{
    public IThing C { get { return new Thing1(); } }
    public IThing D { get { return new Thing2(); } }
}

public class SomeClass
{
    public void PerformTask() {}
}

public static class ExtensionMethods
{
    // This function behaves as I would expect, inferring TContainer
    public static TContainer DoStuffWithThings<TContainer>(this TContainer container, Func<TContainer, IThing> getSomething, Func<TContainer, IThing> getSomethingElse) 
        where TContainer : IContainer
    {
        var something = getSomething.Invoke(container);
        var somethingElse = getSomethingElse.Invoke(container);

        // something and something else are the things we specify in our lambda expressions with respect to the container

        return container;
    }

    // The method in question
    public static TCustomReturnType DoStuffWithThings<TContainer, TCustomReturnType>(this TContainer container, Func<TContainer, IThing> getSomething, Func<TContainer, IThing> getSomethingElse)
        where TContainer : IContainer
        where TCustomReturnType : new()
    {
        var something = getSomething.Invoke(container);
        var somethingElse = getSomethingElse.Invoke(container);

        // Do stuff with the things just as above

        // This time we return our custom type
        return new TCustomReturnType();
    }
}

public class Driver
{
    public static void Main(string[] args)
    {
        var container1 = new Container1();
        var container2 = new Container2();
        // I can do stuff with the things for each container, returning the container each time.

        container1.DoStuffWithThings(c => c.A, c => c.B)
                  .DoStuffWithThings(c => c.B, c => c.A);

        container2.DoStuffWithThings(c => c.C, c => c.D)
                  .DoStuffWithThings(c => c.D, c => c.C);

        // Now we try to do the same but with the custom return type
        container1.DoStuffWithThings<Container1, SomeClass>(c => c.A, c => c.B)
            .PerformTask();
        // As you can see, the compiler requires us to specify Container1 as the container type.
        // Why is it not inferred? It is called from an instance of Container1.
        // The behavior I expect is for container1.DoStuffWithThings<SomeClass>(...) to infer
        // the container type and return a new instance of SomeClass.
    }
}

The basic idea is that when there is only one generic type parameter, the compiler infers the type. When I add a second, the compiler doesn't infer either (It obviously can't infer the second, but I'm not sure why it can't infer the first). My question is why is the type of the container not inferred?

解决方案

The reason is that the second type parameter it's not used in any of the function parameters. So there is no way it's type can be inferred purely from parameter usage.

If you were to have a method signature like this (obviously not equivalent to your code, just an example):

public static TResult DoStuffWithThings<TContainer, TResult>(
    this TContainer container,
    Func<TContainer, TResult> getSomething)

Then it would be able to infer the generic types from the parameters.

If you want to avoid specifying the first parameter you can split the method up into two functions and hide intermediate parameters in a generic type, like this:

public static IntermediateResult<T> DoStuffWithThings<T>(this T container)

public class IntermediateResult<T>
{
    public WithReturnType<TResult>()
}

Then it calling as

var result = container.DoStuffWithThings().WithReturnType<Result>();

这篇关于使用多个泛型类型参数进行类型推断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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