繁体   English   中英

null条件运算符不适用于Func <T> 在通用方法中

[英]null-conditional operator doesn't work with Func<T> inside a generic method

这是一个编译器错误还是有一个特定的选择原因,为什么空条件运算符不能在泛型方法中使用Func

举个例子,下面的代码不能编译

public static T Test<T>(Func<T> func)
{
    return func?.Invoke() ?? default(T);
}

编译器产生的错误是CS0023 Operator '?' cannot be applied to operand of type 'T' CS0023 Operator '?' cannot be applied to operand of type 'T'

我知道你可以做到这一点但是:

public static T Test<T>(Func<T> func)
{
    return func != null ? func() : default(T);
}

那为什么不允许这样呢?

进一步详细说明Action<T>然而按预期工作。

public static void Test<T>(Action<T> action, T arg)
{
    action?.Invoke(arg);
}

更新(2017-01-17):

经过一些更多的研究,即使有以下几点,它也没有多大意义:

假设我们有一个类(参考类型)

public class Foo
{
    public int Bar { get; set; }
}

我们假设我们有一个Func<int>

Func<int> fun = () => 10;

以下作品:

// This work
var nullableBar = foo?.Bar; // type of nullableBar is int?
var bar = nullableBar ?? default(int); // type of bar is int

// And this work
nullableBar = fun?.Invoke(); // ditto
bar = nullableBar ?? default(int); // ditto

这意味着根据应用的逻辑,使用null-conditionalnull-coalescing运算符的值类型的Func<T>应该可以工作。

但是,一旦null-conditional的左手泛型类型是通用的,没有约束,那么它就不能应用相同的逻辑,它应该能够考虑它可以将相同的逻辑应用于值类型引用类型何时明确应用类型。

我知道编译器的约束,它对我来说没有意义,为什么它不允许它以及为什么它希望输出不同,无论它是参考还是值类型,考虑手动应用类型将产生预期的结果。

不幸的是,我相信你已经遇到了编译器的边缘情况。 ?. operator需要返回类的default(RetrunTypeOfRHS)和结构的default(Nullable<RetrunTypeOfRHS>) 因为你没有将T约束为类或结构,所以它无法分辨哪个要提升。

Action<T>工作原因是因为右侧的返回类型对于两种情况都是void ,因此不需要决定要进行哪种促销。

您将需要使用您展示的长形式或者有两种方法对T具有不同的约束

    public static T TestStruct<T>(Func<T> func) where T : struct
    {
        return func?.Invoke() ?? default(T);
    }

    public static T TestClass<T>(Func<T> func) where T : class
    {
        return func?.Invoke(); // ?? default(T); -- This part is unnecessary, ?. already
                                                 // returns default(T) for classes.
    }

您应该在泛型函数上设置约束:

public static T Test<T>(Func<T> func) where T: class
{
    return func?.Invoke() ?? default(T);
}

因为struct不能为null而且 ?. 需要引用类型。


由于Jeroen Mostert的评论,我看看引擎盖下发生了什么。 Func<T>是一个引用类型的委托。 在没有任何T约束的情况下,代码将无法编译。 Error CS0023 Operator '?' cannot be applied to operand of type 'T' Error CS0023 Operator '?' cannot be applied to operand of type 'T' 当您where T: structwhere T: class添加约束时where T: struct将生成基础代码。

代码编写:

    public static T TestStruct<T>(Func<T> func) where T : struct
    {
        return func?.Invoke() ?? default(T);
    }

    public static T TestClass<T>(Func<T> func) where T : class
    {
        return func?.Invoke() ?? default(T);
    }

使用ILSpy生成和反编译的代码:

    public static T TestStruct<T>(Func<T> func) where T : struct
    {
        return (func != null) ? func.Invoke() : default(T);
    }

    public static T TestClass<T>(Func<T> func) where T : class
    {
        T arg_27_0;
        if ((arg_27_0 = ((func != null) ? func.Invoke() : default(T))) == null)
        {
            arg_27_0 = default(T);
        }
        return arg_27_0;
    }

如您所见, T是结构时生成的代码与T是类时的代码不同。 所以我们修好了? 错误。 但是: ?? T是结构时,运算符没有意义。 我认为编译器应该对此进行编译错误 因为用?? 在结构上是不允许的。 #BeMoreStrict

例如:

如果我写:

var g = new MyStruct();
var p = g ?? default(MyStruct);

我收到编译错误:

Error CS0019 Operator '??' cannot be applied to operands of type 'MainPage.MyStruct' and 'MainPage.MyStruct'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM