C#通用方法类型参数推断

时间:2010-05-13 06:45:18

标签: c# type-inference

有什么方法可以概括这里的类型定义吗? 理想情况下,我希望能够更改'testInput'的类型,并在编译时让测试正确地推断出类型。

public static void Run()
{
    var testInput = 3;
    var test = ((Func<int, int>) Identity).Compose<int,int,int>(n => n)(testInput);
    Console.WriteLine(test);
}

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}

public static T Identity<T> (this T value)
{
    return value;
}

更新: 我可以指定传递给Compose的函数的类型,但这仍然指定了行中的类型。

public static void Run()
{
    var testInput = 3;
    var identity = (Func<int, int>) Identity;
    var test = identity.Compose((int n) => n)(testInput);
    Console.WriteLine(test);
}

一点背景;我正在通过Wes Dyer的The Marvel of Monads

4 个答案:

答案 0 :(得分:3)

很明显,因为今晚我正在努力喷出文字,我会自己捅它。我应该注意到我不是C#编译器的专家,我没有阅读规范(其中任何一个......对于任何事情),虽然你链接的那篇文章真的很有趣,但如果我说我就撒谎是任何一种专家(或者甚至全部100%理解)。

除了警告之外,我对你提出的问题是:

  

有什么方法可以概括   这里的类型定义?

我认为简短的回答是否定的。根据提供的信息,C#编译器的类型推断部分根本没有足够的信息来推断使用各种变量的足够信息。

正如其他答案所示,它可以简化。您可以使用@ Lee的IdentityFunc来允许使用var identity进行类型推断。但是,即使添加了这些内容,您的示例代码仍无法推断Compose的所有类型变量。

想象一下以下情况:

public static Func<T, V> Compose<T, U, V>(this Func<U, V> f, Func<T, U> g)
{
    return x => f(g(x));
}

public static T Identity<T> (this T value)
{
    return value;
}

public static Func<T, T> IdentityFunc<T>(this T value)
{
    return (Func<T, T>)Identity;
}

public static void Run()
{
    var a = 3; // a is int
    var i = a.IdentityFunc(); // i is Func<int, int>;
    var test = i.Compose(n => n)(a) // test is expected to be int
}

最初,这可能看起来好像test应该很容易推断到int。但是,i.Compose的返回类型只能在事实之后从其使用中推断出来。 C#编译器显然不允许这样做。

public static void Run()
{
    var a = 3; // a is int
    var i = a.IdentityFunc(); // i is Func<int, int>;
    var c = i.Compose(n => n) // c is Func<T, int> - T cannot be resolved without knowledge of n
    var test = c(a); // ideally have type inference infer c (Func<T, int>) as Func<int, int>
}

在该示例中,在ca一起使用时,编译器必须回顾性地推断对i.Compose<T, U, V>(n => n)的调用的返回类型为Func<int, int>。这在C#编译器中显然是不可能的。取消调用c(a),编译器将不知道c的使用情况,这将消除推断T的任何可能性(不管怎样它都可以)。更高级的类型推理系统可以根据泛型返回的使用来做这种推断(可能是F# - 我不是专家的另一个主题)。

由于Wes Dyer没有提供该特定示例的具体用法,因此不知道是否还有其他一些魔法用于允许您尝试实现的类型推断程度。

Eric Lippert等更多合格人员可以为您提供更高级别的详细信息(以及技术准确性/敏锐度)。我在这里写了一篇关于类型推理的问题的回复,但我找不到它。他的blog有很多很棒的信息。如果您有兴趣,可以尝试联系他。此外,他在这里回答这个问题讨论monads(最后链接回Wes Dyer的文章)买你可能有兴趣阅读它:Monad in plain English? (For the OOP programmer with no FP background)

答案 1 :(得分:2)

您可以编写一个扩展方法来返回类型的Identity函数:

public static Func<T, T> IdentityFunc<T>(this T value)
{
    return (Func<T, T>)Identity;
}

(或只是return v => value;

然后您的测试成为

var testInput = 3; 
var identity = testInput.IdentityFunc();
test = identity.Compose((int n) => n)(testInput);

答案 2 :(得分:1)

我能得到的最接近的是明确输入n =&gt;的参数。 n lambda:

var test = ((Func<int, int>)Identity).Compose((int n) => n)(testInput);

答案 3 :(得分:1)

我认为你无法实现理想; C#类型推断不起作用。

你可能喜欢F#。