【问题标题】:Extra generic parameter in generic extension methods?泛型扩展方法中的额外泛型参数?
【发布时间】:2010-02-26 22:00:26
【问题描述】:

我想为泛型类 A 创建一个扩展方法,它采用另一个泛型类型(在本例中为 TC),但我想这不可能吗?

class Program
{
    static void Main(string[] args)
    {
        var a = new A<B, B>();
        a.DoIt<B>();
    }
}

static class Ext
{
    public static A<TA, TB> DoIt<TA, TB, TC>(this A<TA, TB> a)
    {
        return a;
    }
}

class A<TA, TB> { }
class B { }

【问题讨论】:

  • 一个有趣的想法,我们不支持。本质上,这将是对泛型方法的泛型类型参数“部分评估”的一种形式;通常是对方法的形式参数进行柯里化和部分评估。当然有些语言可以轻松地对形式进行部分评估,但是有人知道是否有语言(函数式或其他语言)允许对泛型类型参数进行部分评估吗?那会很整洁。
  • @Eric - 这就是 F# 的扩展方法的工作原理。此外,F# 允许您将_ 用于您不想指定且可以推断的类型参数,因此即使在非扩展方法调用中,您也可以使用Foo&lt;_,_,TypeICareAbout&gt;(...) 而不是Foo&lt;LongTypeName,AnotherInferableType,TypeICareAbout&gt;(...),这通常是可读性的一大胜利。另一方面,F# 不允许封闭泛型类型上的扩展成员,这是 C# 的一个很好的特性。
  • @kvb:很酷,感谢您的留言。自 1993 年以来,我实际上还没有用任何 ML 变体编写过程序,所以我有点生疏了。我真的应该用 F# 编写一些程序,看看它是如何工作的。

标签: c# generics type-inference


【解决方案1】:

如果你能接受轻微的语法变化,那么这是可能的。

改成:

var a = new A<B, B>(); 
a.Do().It<B>(); 

诀窍在于 Do 方法是 A&lt;TA, TB&gt; 上的扩展方法:

public static Doer<TA, TB> Do<TA, TB>(this A<TA, TB> a)
{
    return new Doer<TA, TB>(a);
}

诀窍在于,此签名允许类型推断从a 获取 TA 和 TB,因此您不必明确指定它们。

Doer 类提供了你需要的泛型方法:

public class Doer<TA, TB>
{
    public void It<TC>() { }
}

【讨论】:

    【解决方案2】:

    不,这是可能的,但您必须为编译器提供一些可接受的“TC”上下文。第三个参数 TC 在您的代码中的其他任何地方都没有使用,因此它可以是任何东西,因此编译器会抱怨。但是,如果将传入参数添加到类型为 TC 的扩展方法中,则可以实现编译器可以推断 TC 的实际类型的情况,然后在调用时甚至不必指明类型是什么方法:

    class Program
    {
        static void Main(string[] args)
        {
            var a = new A<B, B>();
            string tc = "Hi!";
            a.DoIt(tc);
        }
    }
    
    static class Ext
    {
        public static A<TA, TB> DoIt<TA, TB, TC>(this A<TA, TB> a, TC c)
        {
            return a;
        }
    }
    
    class A<TA, TB> { }
    class B { }
    

    但是你必须给编译器一些上下文。

    话虽如此,指定泛型参数是一项全有或全无的努力。编译器要么可以推断出每个泛型类型参数的类型,要么不能,你必须告诉它它们都是什么。

    【讨论】:

    • @David Morton:你想说“类型推断”,这是用来描述特性的术语。
    • @casperOne 我想我打败了你。我在发布后立即编辑了我的原始帖子以进行一般交流和“条款”。
    • 实际上,我只想要类型,而不是实例 =/ a.DoIt(typeof(B)) 只是不如 a.DoIt() 好看,仅此而已,没什么大不了。谢谢!
    【解决方案3】:

    你是对的,这是不可能的。您必须指定所有类型参数(TATBTC),或者一个都不指定(由编译器的类型推断决定)。

    几种可能性:

    • DoIt 转换为实例方法(尽管我猜你是故意将其作为扩展方法)
    • DoIt 添加另一个参数以某种方式约束TC,这意味着类型推断将起作用

    对于第二个例子,请看Enumerable.Select:它有两个类型参数,用于源类型和目标类型,但它们都是从传递给Select 的参数中推断出来的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多