1

当我试图回答这个问题时:

是否可以摆脱 Service 类中的 TClient 泛型类型

我发现了一个奇怪的用法,我从来没有设计过这种不可编译的语法,下面是我遇到的一个代表:

interface IGeneric<T> {
}

partial class SomeClass {
    // won't compile
    public static void SomeMethod<U>(Action<T> d) where T: IGeneric<U> {
    }
}

即使声明为:

class Concrete: IGeneric<object> {
}

partial class SomeClass {
    public static void SomeMethod<U>(Action<IGeneric<U>> d) { // compiles
    }
}

不会使以下代码可编译:

var d=default(Action<Concrete>);
SomeClass.SomeMethod(d); // won't compile

我不知道在涉及两个类型参数的情况下可以使用的语法。

所以我想知道这种反向类型推断是否有语法?还是解决方法?

4

2 回答 2

4

简单回答是不。这甚至与类型推断无关——它与类型约束有关。您只能添加约束在同一声明中引入的类型参数。所以这:

public static void SomeMethod<U>(Action<T> d) where T: IGeneric<U>

是无效的,因为您试图TU, 当它U实际上是在方法声明中引入时进行约束。事实上,T它本身在任何地方都不是类型参数——但即使SomeClassT.

在许多与此类似的情况下,您可以通过非泛型类型中的额外静态方法,通过类型推断创建泛型类型的实例 - 但具体情况通常是您有两个类型参数并且您想要明确指定其中之一

需要注意的重要一点是,一个Action<Concrete>简单的不是一个Action<IGeneric<object>>。例如,Concrete可能会暴露一些 anAction<Concrete>可能依赖的额外属性 - 但给定 anAction<IGeneric<object>>你可以很容易地用不同的实现来调用它IGeneric<object>。您现有的SomeMethod尝试通过特定Action<U>而不是解决该问题Action<IGeneric<T>>- 但此时使用该操作相对困难。即使类型推断有效,这也很少(根据我的经验)是一种实用的方法。

一旦您更改为真正的协变委托(并假设您使用的是 C# 4),除非您关心,否则U您可以简单地使用不同的签名:

using System;

interface IGeneric<T> {}

class SomeClass
{    
    public static void SomeMethod<T>(Func<IGeneric<T>> d) {}
}

class Concrete: IGeneric<object> {}

class Test
{
    static void Main()
    {
        var d = default(Func<Concrete>);
        // This compiles fine
        SomeClass.SomeMethod(d);
    }
}
于 2013-04-26T06:04:44.883 回答
2

问题是您试图将 aAction<T>视为 T 中的协变,但事实并非如此。事实上,它是逆变的。

例如,如果你有一个协变委托,像这样。

delegate T CovariantCall<out T>();

你可以很容易地做你所要求的。

CovariantCall<IGeneric<object>> covariant = default(CovariantCall<Concrete>);

您的第一个示例无法编译,因为您T在方法的声明类型参数列表中省略了 。不过,这是一个更好的主意,而且它之所以有效,是因为约束只验证并且不影响参数方差,但是您必须明确指定您正在寻找哪些参数并且无法推断它。

public static void SomeMethod<T, U>(Action<T> d) where T: IGeneric<U>
{ 
    ...
}

SomeClass.SomeMethod<Concrete, object>(default(Action<Concrete>));

C# 类型推断的能力是有限的,这就是其中之一。如果不明确指定类型,您将无法执行您所要求的操作。

于 2013-03-25T19:53:21.717 回答