“一次性”实例化和扩展类时参考祖先的属性

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

感谢 这个问题的答案 当我将类扩展为某种匿名类型时,我能够重写 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
3个回答
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 参数/属性。


0
投票

我建议更改

ExecutePropAsync
的签名以接受两个额外的整数,然后您可以在执行
MyAsyncBackgroundJob<TExecuteArgs>
类中的方法时传递它们。

这样,您就可以通过参数将

_myVariable
MyProp
直接传递给方法。并且在方法中有参数,让我们在其中使用它们:)

这是您稍微重构的示例。

internal static class testarea
{
    internal static void Test()
    {
        var anonymous = new MyAsyncBackgroundJob<string>
        {
            ExecutePropAsync = (string s, int myVariable, int myProp) => {
                string output = null;

                if (s == "example") output = s + s;

                if (myVariable == 1) output = s + s;

                if (myProp == 1) output = s + s;

                return Task.FromResult(output);
            }
        };
    }
}

public class MyAsyncBackgroundJob<TExecuteArgs>
{

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

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


    public MyAsyncBackgroundJob()
    {
    }

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

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
都不起作用,因为您无法访问类定义范围之外的受保护字段/属性。

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