实例化扩展类的匿名类型时参考祖先属性

问题描述 投票:0回答:2

感谢 这个问题的答案 当我将类扩展为匿名类型时,我能够重写 C# 中的虚拟方法。

但是是否可以引用祖先类的类变量或属性?

这是我的 C# 代码的简化版本:

public class MyAsyncBackgroundJob<TExecuteArgs> {

    public Func<TExecuteArgs, Task> ExecutePropAsync { get; set; }

    protected int _myVariable = 1;  // just an example
    public int MyProp { get; set; } = 2;  // just an example


    public MyAsyncBackgroundJob() {
    }

    public override Task ExecuteAsync(TExecuteArgs args) {
        return ExecutePropAsync(args);
    }
}

以及我想如何使用它:

var anonymous = new MyAsyncBackgroundJob<string> {
    ExecutePropAsync = (string s) => {
        string output = null;

        // this example works:
        if (s == "example") output = s + s;

        // this example DOESN'T works:
        if (_myVariable == 1) output = s + s;

        // this example DOESN'T works:
        if (MyProp == 1) output = s + s;

        return Task.FromResult(output);
    }
};

// Note: in the real life ExecuteAsync(TExecuteArgs args) is called automatically by the framework
await anonymous.ExecutePropAsync("example");

注意:在现实生活中

ExecuteAsync(TExecuteArgs args)
是由框架自动调用的

c# anonymous-types anonymous-class
2个回答
0
投票

首先你错了。变量

anonymous
不是匿名的,它是强类型的
MyAsyncBackgroundJob<string>
,但 lambda 表达式确实会生成匿名类型。

您的问题是因为您尝试在 lambda 表达式的范围内引用

MyAsyncBackgroundJob<string>
的属性,与类定义的范围内不同,该范围内没有隐式
this
对象,您必须提供引用像
obj.MyProp
这样的物体。

但是当你像这样使用对象初始化器时:

var obj = new MyAsyncBackgroundJob<string>{}
,实际上,这个变量
obj
只会在对象初始化器完成后才会被赋值,所以你无法在lambda表达式中访问它。您可以预先初始化它。

MyAsyncBackgroundJob<string> job = null;

job = new MyAsyncBackgroundJob<string> {
    ExecutePropAsync = (string s) => {
        string output = null;

        // this example works:
        if (s == "example") output = s + s;

        // this example DOESN'T works:
        //if (job._myVariable == 1) output = s + s;

        if (job.MyProp == 1) output = s + s;

        return Task.FromResult(output);
    }
};

但是,无论如何,

job._myVariable
都不起作用,因为您无法访问类定义范围之外的受保护字段/属性。


0
投票

可以给

ExecutePropAsync
添加一个额外的参数,这样调用的时候就可以传递
this
了。然后在使用站点,您可以通过该参数访问
this

public Func<MyAsyncBackgroundJob<TExecuteArgs>, TExecuteArgs, Task> ExecutePropAsync { get; init; }

public Task ExecuteAsync(TExecuteArgs args) {
    return ExecutePropAsync(this, args);
}

现在可以编译了:

var job = new MyAsyncBackgroundJob<string> {
    ExecutePropAsync = (self, s) => {
        string output = null;
        if (s == "example") output = s + s;
        if (self.MyProp == 1) output = s + s;

        return Task.FromResult(output);
    }
};

但是,这种方法不允许您访问受保护的成员。毕竟,您分配给

ExecutePropAsync
的 lambda 不在
MyAsyncBackgroundJob
或其任何子类中。

虽然您也可以以相同的方式将所需的受保护属性作为 lambda 的参数传递(也许可以先将它们包装在另一个类中,如果有很多),但我个人此时会创建

MyAsyncBackgroundJob
的子类,哪个更易于维护。否则,每次在
MyAsyncBackgroundJob
中添加受保护成员时,都必须更新包装类中的 lambda 参数/属性。

© www.soinside.com 2019 - 2024. All rights reserved.