【问题标题】:out parameter modifier in Func delegate (C#)Func 委托中的 out 参数修饰符(C#)
【发布时间】:2019-03-07 12:31:56
【问题描述】:

我是 C# 的初学者,只是一个关于 Func 委托的问题:

public delegate TResult Func<in T,out TResult>(T arg);

我可以理解需要在 T 之前放置 in 关键字,因为我们不想修改源输入,但是 out 在 TResult 之前呢?这不是意味着我们需要修改输出,但为什么呢?我们不是有时只是动态生成返回对象吗,假设我们有一个委托:

Func<string, bool> nameFilter = str => str[0] == 'S';

所以它检查一个字符串,看它的第一个字符是'S',然后返回true或false,所以我们动态返回这个布尔值,out关键字在这里做什么?没有什么需要改回来的吗?

【问题讨论】:

标签: c# .net


【解决方案1】:

简短的回答

您很少需要担心Generic 类型定义中的inout 关键字。使用in/out 泛型类型参数定义的类通常会在您使用它时“正常工作”,我敢打赌大多数开发人员永远不会在自己的代码中编写这样的定义。

更长的答案

要获得完整的解释,您应该阅读Covariance and ContravarianceVariance in Delegates。我的其余答案只是一些说明性示例代码。

为了简化解释,我将通过Action&lt;T&gt;Func&lt;TResult&gt;分别解释inout,而不是Func&lt;T,TResult&gt;

示例均使用以下两个类:

class BaseClass {}
class DerivedClass : BaseClass {}

协方差:out

对于这个例子,我模仿了Func&lt;out TResult&gt;,但删除了out(协方差)修饰符来展示它的效果。协方差允许我们在任何期望返回 BaseType 的函数的地方使用 返回 DerivedType 的函数。

class CovarianceExamples
{
    // This is similar to System.Func<out TResult>(), but with covariance removed
    delegate TResult InvariantFunc<TResult>(); 

    void InvariantFuncExample()
    {
        // Ignore the values of these variables; it's the types that are important
        InvariantFunc<BaseClass> baseFunc = null;
        InvariantFunc<DerivedClass> derivedFunc = null;

        baseFunc = baseFunc; // Allowed
        baseFunc = derivedFunc; // Not allowed; compile error!
    }

    void CovariantFuncExample()
    {
        // Ignore the values of these variables; it's the types that are important
        Func<BaseClass> baseFunc = null;
        Func<DerivedClass> derivedFunc = null;

        baseFunc = baseFunc; // Allowed
        baseFunc = derivedFunc; // Allowed
    }
}

逆变:in

对于这个例子,我模仿了Action&lt;in T&gt;,但删除了in(逆变)修饰符来展示它的效果。逆变允许我们在任何期望接受DerivedType 的操作的地方使用接受 BaseType 的操作。

class ContravarianceExamples
{
    // This is similar to System.Action<in T>(T), but with contravariance removed
    delegate void InvariantAction<T>(); 

    void InvariantActionExample()
    {
        // Ignore the values of these variables; it's the types that are important
        InvariantAction<BaseClass> baseAction = null;
        InvariantAction<DerivedClass> derivedAction = null;

        baseAction = baseAction; // Allowed
        derivedAction = baseAction; // Not allowed; compile error!
    }

    void ContravariantActionExample()
    {
        // Ignore the values of these variables; it's the types that are important
        Action<BaseClass> baseAction = null;
        Action<DerivedClass> derivedAction = null;

        baseAction = baseAction; // Allowed
        derivedAction = baseAction; // Allowed
    }
}

【讨论】:

    猜你喜欢
    • 2012-08-26
    • 2016-08-07
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-03
    相关资源
    最近更新 更多