Func<;T>;作为类成员,访问实例的其他成员

本文关键字:成员 访问 其他 实例 lt gt Func | 更新日期: 2023-09-27 17:59:06

我有一个问题,是否可以(如果可以,如何)从Func<T, TResult>委托内部访问class成员。

例如,我有以下class:

class NinjaTurtle
{
    public string Sound { get; set; }
    public Func<string, string> DoNinjaMove { get; set; }
}

现在我想做这个

NinjaTurtle leonardo = new NinjaTurtle();
leonardo.Sound = "swiishhh!";
leonardo.DoNinjaMove = (move) => {
    if(move == "katana slash") return leonardo.Sound;
    return "zirp zirp zirp";
}

问题是,当我定义回调函数时,如何正确地访问属性Sound?只使用函数外部对实例的引用可以吗?当我将对象传递给另一个方法时,或者甚至当它是dll的一部分时,并且我将从dll中的函数返回对象leonado时,这仍然有效吗?它会"幸存"序列化/反序列化吗?

(感谢Vladimir和Lee,这个问题现在更具体了,我想知道)。

Func<;T>;作为类成员,访问实例的其他成员

您可以使用闭包。闭包将是一个匿名委托或lambda表达式,它可能引用外部范围中的变量、方法、属性、事件或任何东西(哎呀,这是您的情况!)。

leonardo.DoNinjaMove = (move) => {
    // THIS IS VALID! IT'S A CLOSURE! You can access leonardo reference within
    // the closure!!
    if(move == "katana slash") return leonardo.Sound; 
    return "zirp zirp zirp";
}

总之,DoNinjaMove就是Func<string, bool>。如果要返回Sound值,则应将其重构为Func<string, string>

关于闭包是如何工作的,以及为什么你可以在闭包中安全地使用外部作用域的引用的更多细节可以在另一个问答中找到;StackOverflow中的A:

  • 关闭是如何在幕后工作的?(C#)

关于在处理附属程序集时使用闭包是否有效

是的,这没有问题。闭包是大多数现代语言所拥有的一个非常有趣的功能,也是包含函数式编程的语言的必备功能。无论如何,这是必备功能!:)

如果您从谷歌来到这里,特别想将Lambda函数编码为类主体中声明的类成员,请继续阅读…

我通过谷歌找到了这篇文章,因为我正在寻找一种方法来声明Lambda Func为类本身的成员方法。您可以在类内部声明Func,但不能在同一行中直接赋值给它。示例:

public class myClass {
    public Func<string,string> DoNinjaMove;  //Can't declare method body here.
}

解决方案是在类的构造函数中分配Lambda函数体,如下所示:

public class myClass {
    public Func<string,string> DoNinjaMove;  //Can't declare method body here.
    public myClass()
    {
        DoNinjaMove = (someString) =>
        {
            //Do something here
            return anotherString;
        }
    }
}

现在DoNinjaMove是myClass的成员,它的主体也在myClass中声明。DoNinjaMove可以访问myClass的所有成员,并且您可以将DoNinjaMove传递给其他类/对象,让它们调用它。

除非你完全知道自己在做什么,否则我可能不会推荐这种设计模式。在我的例子中,我使用的另一个库要求我向它传递一个具有特定输入和返回类型的Lambda函数,但为了美观和封装,我需要该函数成为我自己类的成员,在那里它可以访问类数据。这就是我想出的解决方案。

这将在闭包中捕获变量leonardo,并且会起作用,但我认为这不是一个好的设计,但如果没有上下文,很难提出不同的建议。

var leonardo = new NinjaTurtle();
leonardo.Sound = "swiishhh!";
leonardo.DoNinjaMove = (move) =>
{
   if (move == "katana slash")
   {
      return leonardo.Sound;
   }
   else
   {
      return "zirp zirp zirp";
   }
}

您可能需要考虑使用Func<NinjaTurtle, String, String>并显式传递海龟。

leonardo.DoNinjaMove = (turtle, move) =>
{
   if (move == "katana slash")
   {
      return turtle.Sound;
   }
   else
   {
      return "zirp zirp zirp";
   }
}

但这对我来说仍然不是一个令人信服的设计