Dan*_*ury 12 c# oop programming-languages
由于我不是编程语言方面的专家,我很清楚这可能是一个愚蠢的问题,但是我可以告诉C#处理匿名方法和闭包,将它们变成匿名嵌套类的实例方法[1] ,实例化这个类,然后将委托指向那些实例方法.
看来这个匿名类只能被实例化一次(或者我错了吗?),那么为什么不让匿名类变为静态呢?
[1]实际上,看起来有一个闭包类和一个不捕获任何变量的匿名方法,我不完全理解其中的任何一个.
Eri*_*ert 28
我很清楚这可能是一个愚蠢的问题
不是.
C#通过将匿名方法和闭包设置为匿名嵌套类的实例方法,实例化此类,然后将委托指向这些实例方法来处理匿名方法和闭包.
C#有时会这样做.
看来这个匿名类只能被实例化一次(或者我错了吗?),那么为什么不让匿名类变为静态呢?
如果这是合法的,C#会让你更好.它根本不构成封闭类.它使匿名函数成为当前类的静态函数.
是的,你错了.在你只能分配一次委托的情况下,C#确实可以逃脱它.
(严格来说,这并不完全正确;有一些模糊的情况没有实现这种优化.但是大多数情况下都是如此.)
实际上,看起来有一个闭包类和一个不捕获任何变量的匿名方法,我不完全理解其中的任何一个.
你已经把手指放在你没有充分理解的东西上.
我们来看一些例子:
class C1
{
Func<int, int, int> M()
{
return (x, y) => x + y;
}
}
Run Code Online (Sandbox Code Playgroud)
这可以生成为
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;
}
}
Run Code Online (Sandbox Code Playgroud)
不需要新课程.
现在考虑:
class C2
{
static int counter = 0;
int x = counter++;
Func<int, int> M()
{
return y => this.x + y;
}
}
Run Code Online (Sandbox Code Playgroud)
你知道为什么用静态函数不能生成这个吗? 静态函数将需要访问this.x但如果是这样的静态函数?没有一个.
所以这一个必须是一个实例函数:
class C2
{
static int counter = 0;
int x = counter++;
int Anonymous(int y) { return this.x + y; }
Func<int, int> M()
{
return this.Anonymous;
}
}
Run Code Online (Sandbox Code Playgroud)
此外,我们不能再将代理缓存在静态字段中; 你知道为什么吗?
练习:委托可以缓存在实例字段中吗?如果不是,那么是什么阻止了这种合法性呢?如果是,那么反对实施这种"优化"的一些论点是什么?
现在考虑:
class C3
{
static int counter = 0;
int x = counter++;
Func<int> M(int y)
{
return () => x + y;
}
}
Run Code Online (Sandbox Code Playgroud)
这不能作为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
Run Code Online (Sandbox Code Playgroud)
现在,代表们不仅需要知道传入的值,this.x还需要知道y传入的值.必须将其存储在某处,因此我们将其存储在字段中.但它不能是C3的一个领域,因为那么我们如何告诉b使用123并g使用789的值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;
}
}
Run Code Online (Sandbox Code Playgroud)
练习:现在假设我们有C4<T>一个泛型方法M<U>,其中lambda在T和U类型的变量上被关闭.描述现在必须发生的codegen.
练习:现在假设我们让M返回一个代表元组,一个存在()=>x + y,另一个存在(int newY)=>{ y = newY; }.描述两位代表的codegen.
练习:现在假设M(int y)返回类型Func<int, Func<int, int>>,我们返回a => b => this.x + y + z + a + b.描述codegen.
练习:假设一个lambda关闭了两个this并且本地执行base非虚拟调用.base出于安全原因,从不直接在虚方法的类型层次结构中的类型内的代码进行调用是非法的.描述在这种情况下如何生成可验证的代码.
练习:把它们放在一起.你如何为所有本地人使用getter和setter lambdas为多个嵌套lambda做codegen,由类和方法作用域的泛型类型参数化,这些base调用是什么?因为这是我们实际必须解决的问题.