【问题标题】:How to Pass a Func<string, string> to a function that takes a Func<object, object>如何将 Func<string, string> 传递给采用 Func<object, object> 的函数
【发布时间】:2020-10-23 10:06:29
【问题描述】:

好的,我有这个简单的类

    private class TFTheOne
    {
        private object value;

        public TFTheOne(object value)
        {
            this.value = value;
        }

        public TFTheOne Bind(Func<object, object> func)
        {
            value = func(value);
            return this;
        }

        public void PrintMe()
        {
            Console.WriteLine(value);
        }
    }

还有这个功能

    public static string ReadFile(string filePath)
    {
        return File.ReadAllText(filePath);
    }

现在当我尝试将ReadFile 传递给TFTheOne.Bind 函数时

 new TFTheOne(args[0]).Bind(ReadFile);

我收到此错误消息

错误 CS1503 参数 1:无法从“方法组”转换为 '功能'

即使我尝试投射 ReadFile

new TFTheOne(args[0]).Bind((Func<object, object>)ReadFile);

有没有办法解决这个问题?

【问题讨论】:

  • 方法为什么取Func&lt;object, object&gt;?您的string 输入如何映射到object 输入,您的object 输出如何映射到您的string 输出?这似乎是您可能会引入错误的地方。
  • 如果 Bind 最终用非字符串的东西调用这个函数会发生什么?
  • 一个简单的桥梁类似于.Bind(o =&gt; ReadFile(o as string)),但您确实需要(对自己)回答我在第一条评论中提出的问题。
  • 你的课可能很简单,但它很复杂,你的意图也不清楚。这似乎是某种 Fluent Api。然而,你真正想要实现的是什么?
  • @TheGeneral 编码作业作为对 Monads 的介绍。 C# 绝对不是我的首选,但我现在有点坚持。

标签: c# .net delegates func


【解决方案1】:

Func&lt;T, TResult&gt;T逆变的,因此只有不太具体的类型可以用作输入。

在您的情况下,您需要包装您的 ReadFile 方法以确保它适用于任何 object

根据您的要求,这样的方法会起作用:

new TFTheOne(args[0]).Bind(o => ReadFile(o?.ToString()));

虽然“更好”的设计是重载Bind

public TFTheOne Bind(Func<string, object> func)
{
    value = func(value);
    return this;
}

现在因为TResult协变的,这应该可以正常编译:

new TFTheOne(args[0]).Bind(ReadFile);

【讨论】:

    【解决方案2】:

    你不能那样做。考虑这种情况:您的类 TFTheOne 保存一个整数值,如果允许您这样做,那么您的函数会在您调用它时崩溃,因为它需要一个字符串。

    你可以做的是创建一个包围你的Func&lt;string, string&gt;()的lambda,并检查传递给它的参数是否真的是一个字符串:

    .Bind((o) => o is string ? ReadFile((string)o) : null);
    

    【讨论】:

    • 看代码,特别是Console.WriteLine(value),似乎在对象上调用ToString()比使用null更合适。
    • @JohnathanBarclay 这取决于,如果 o 是一个类实例 ToString 根本没有用。
    • 已经有一个方法在value 上调用ToString()(通过使用Console.WriteLine(object))。使用您的实现,当您将 string 传递给构造函数或通过 Bind 时,您现在会有不同的行为,这肯定是不可取的。
    猜你喜欢
    • 2012-05-13
    • 1970-01-01
    • 2021-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多