为什么C#将匿名方法和闭包实现为实例方法,而不是静态方法?

丹尼尔·麦克劳里

由于我不是编程语言的专家,我很清楚这可能是一个愚蠢的问题,但是尽我所能告诉C#通过将匿名方法和闭包转换为匿名嵌套类的实例方法来处理它们[1]。 ,实例化此类,然后将委托指向这些实例方法。

看来该匿名类只能实例化一次(或者我对此是否错?),那么为什么不将匿名类设为静态呢?


[1]实际上,似乎有一个用于闭包的类和一个用于不捕获任何变量的匿名方法的类,我不完全了解这两个类的基本原理。

埃里克·利珀特

我很清楚这可能是一个愚蠢的问题

不是。

C#通过使匿名方法和闭包成为匿名嵌套类的实例方法,实例化此类,然后将委托指向这些实例方法,来处理匿名方法和闭包。

C#有时会这样做

看来该匿名类只能实例化一次(或者我对此是否错?),那么为什么不将匿名类设为静态呢?

在合法的情况下,C#会帮助您更好。它根本不构成闭包类。它使匿名函数成为当前类的静态函数。

是的,你错了。如果仅分配一次委托就可以解决问题,C#确实可以解决。

(严格地说,这并不是完全正确的;在某些模糊的情况下,未实现此优化。但在大多数情况下,是没有实现的。)

实际上,似乎有一个用于闭包的类和一个用于不捕获任何变量的匿名方法的类,我不完全了解这两个类的基本原理。

您已经将手指放在您没有充分理解的事物上。

让我们看一些例子:

class C1
{
  Func<int, int, int> M()
  {
    return (x, y) => x + y;
  }
}

这可以生成为

class C1
{
  static Func<int, int, int> theFunction;
  static int Anonymous(int x, int y) { return x + y; }
  Func<int, int, int> M()
  {
    if (C1.theFunction == null) C1.theFunction = C1.Anonymous;
    return C1.theFunction;
  }
}

不需要新的课程。

现在考虑:

class C2
{
  static int counter = 0;
  int x = counter++;
  Func<int, int> M()
  {
    return y => this.x + y;
  }
}

您知道为什么不能使用静态函数生成它吗?静态函数将需要访问this.x,但是静态函数中this哪里没有一个。

因此,这必须是一个实例函数:

class C2
{
  static int counter = 0;
  int x = counter++;
  int Anonymous(int y) { return this.x + y; }
  Func<int, int> M()
  {
    return this.Anonymous;
  }
}

同样,我们不能再将委托缓存在一个静态字段中。你明白为什么吗?

练习:可以将委托缓存在实例字段中吗?如果否,那么是什么阻止了这种行为合法化?如果是,那么反对实现这种“优化”的一些理由是什么?

现在考虑:

class C3
{
  static int counter = 0;
  int x = counter++;
  Func<int> M(int y)
  {
    return () => x + y;
  }
}

不能将其作为C3的实例函数生成。你明白为什么吗?我们需要能够说:

var a = new C3();
var b = a.M(123);
var c = b(); // 123 + 0
var d = new C3();
var e = d.M(456);
var f = e(); // 456 + 1
var g = a.M(789);
var h = g(); // 789 + 0

现在,代表不仅需要知道的值,this.x而且还需要知道y传入的值。该值必须存储在某个地方,因此我们将其存储在字段中。但这不能是C3的字段,因为那么我们如何告诉b使用123和g789来表示值y它们具有的相同实例,C3但是具有两个不同的值y

class C3
{
  class Locals
  {
    public C3 __this;
    public int __y;
    public int Anonymous() { return this.__this.x + this.__y; }
  }
  Func<int> M(int y)
  {
    var locals = new Locals();
    locals.__this = this;
    locals.__y = y;
    return locals.Anonymous;
  }
}

练习:现在假设我们有C4<T>一个通用方法M<U>,其中lambda在类型T和U的变量上关闭。描述现在必须发生的代码生成。

练习:现在假设我们有M返回一个代表的元组,一个是()=>x + y,另一个是(int newY)=>{ y = newY; }描述两个委托的代码生成。

练习:现在假设M(int y)返回类型Func<int, Func<int, int>>,我们返回a => b => this.x + y + z + a + b描述代码。

练习:假设同时关闭了一个lambdathis和一个local进行了base非虚拟调用。base出于安全考虑,从类型内部的代码而不是直接在虚拟方法的类型层次结构中进行调用是非法的描述在这种情况下如何生成可验证的代码。

练习:将它们放在一起。您如何使用多个getter和setter lambda来对所有嵌套lambda进行编码生成,而所有locals都由在base调用类和方法范围内的泛型类型进行参数化因为那是我们实际上必须解决的问题

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

为什么C#默认将方法实现为非虚拟方法?

为什么将返回IAsyncEnumerable的异步方法实现为类而不是结构?

为什么`_isurl`是实例方法而不是numpy`DataSource`的静态方法?

为什么C#编译器可以“看到”未引用的DLL中的类的静态属性,而不是其实例方法?

为什么C#将整数类型实现为结构而不是原始类型?

为什么C#编译器在静态方法调用实例方法的地方不会出错?

是否可以将翻转实现为Scala函数(而不是方法)

为什么某些numpy调用未实现为方法?

为什么C#不允许静态方法实现接口?

为什么将静态方法视为方法?

为什么withLatestFrom RxJS方法不是静态的?

为什么不能修改内联方法的闭包参数?

如果字段和方法是静态的,为什么新建一个类的实例毫无意义/毫无意义?[C#]

C# 为什么我可以通过属性访问非静态类的方法和属性,而无需先创建该类的实例?

Blazor JSInterop 静态与实例 C# 方法

PHP闭包:为什么绑定到静态类时匿名函数声明中的“静态”?

为什么通过实例调用静态方法不是Java编译器的错误?

为什么方法局部静态变量绑定到类而不是实例?

为什么静态方法中的本地类不是静态的

在React中,为什么将render方法绑定到组件实例而不是自定义方法?

C#中的递归和匿名方法

为什么iter不是实例的方法而__iter__是实例?

理解闭包和方法论

从数组中调用方法和闭包

为什么一个接口的通用方法可以实现为Java的非通用?

C#中的“静态方法”是什么?

为什么使用单例而不是静态方法?

为什么最好从该方法的类的实例中静态调用静态方法?

静态方法和实例方法之间的区别