首页 > 解决方案 > 如何在不使用反射的情况下获取传递给构造函数的字段或属性的当前值

问题描述

我有一类在其他地方管理的设置,以及许多需要知道与自己相关的设置的当前值的工人类实例。设置可能随时更改。

在 C++ 中,我可以简单地将相关设置的引用传递给工作类构造函数。我应该如何在 C# 中完成这个?反射是唯一强大而简洁的解决方案吗?

下面的代码说明了我想要完成的事情,但它当然会失败,因为设置的值是在实例化工作者时复制的。我有哪些选择可以在需要时获取这些值?

如何修改此代码以实现所需的行为而不会造成混乱?

using System;
namespace TestSettings
{
    public static class Settings
    {
        public static bool setting1 { get; set; } = true;
        public static bool setting2 { get; set; } = false;
    }
    public class mWorker
    {
        private string wName;
        private bool wSetting;
        public mWorker(string _name, bool _setting)
        {
            wName = _name;
            wSetting = _setting;
        }
        public void doWork()
        {
            var onOff = (wSetting) ? "ON" : "OFF";
            Console.WriteLine($"Worker {wName} is turned {onOff}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            // Settings are passed by value when each worker is 
            // instantiated. I want to pass the constructor   
            // something that allows each setting to be read 
            // dynamically whenever it is used. 
            mWorker worker1 = new mWorker("W1", Settings.setting1);
            mWorker worker2 = new mWorker("W2", Settings.setting2);

            Console.WriteLine("\n=====================");
            worker1.doWork();   // Result: "Worker W1 is turned ON"
            worker2.doWork();   // Result: "Worker W2 is turned OFF"

            Settings.setting1 = false;
            Settings.setting2 = true;

            Console.WriteLine("\n=====================");
            worker1.doWork();   // Desired result: "Worker W1 is turned OFF"
            worker2.doWork();   // Desired result: "Worker W2 is turned ON"
            Console.ReadLine();
        }
    }
}

我已经阅读了许多关于解决方法的 SO 问题和答案,因为属性不能通过引用传递,并且有很多提示和建议,但他们都没有以任何方式回答我的问题,我可以将其转化为决定和一个可行的解决方案。我回到 John Skeet 的 C# 书籍并重新阅读它,我确信答案就在某个地方——但我仍然没有看到它。

我知道我可以传递一个属性名称并使用反射来获取值。魔术字符串让我感到不舒服,但也许 NameOf() 可以解决这个问题。我知道我可以创建一个命名设置类并编写一个函数来返回给定设置名称的值。我知道代表可能会提供帮助,但我看到的示例似乎每个设置都需要一个代表,我希望有一个简洁的解决方案。

我假设我可以放弃属性并使用公共字段,传递对该字段的引用,但是 SO 上的一些聪明人在与我的问题相似(但不相同)的问题上建议反对这种方法。

我不禁觉得这一定是一个普遍需要的功能,并希望有一种普遍接受的方法来在 C# 中处理它。

标签: c#

解决方案


如果您需要保持设置类原样,您可以执行以下操作:

public static class Settings
{
    public static bool setting1 { get; set; } = true;
    public static bool setting2 { get; set; } = false;
}

public class mWorker
{
    private string wName;
    private Func<bool> wSetting;

    public mWorker(string _name, Func<bool> _setting)
    {
        wName = _name;
        wSetting = _setting;
    }
    public void doWork()
    {
        var onOff = wSetting() ? "ON" : "OFF";
        Console.WriteLine($"Worker {wName} is turned {onOff}");
    }
}

class Program
{
    void Main()
    {
        // Settings are passed by value when each worker is 
        // instantiated. I want to pass the constructor   
        // something that allows each setting to be read 
        // dynamically whenever it is used. 
        mWorker worker1 = new mWorker("W1", () => Settings.setting1);
        mWorker worker2 = new mWorker("W2", () => Settings.setting2);

        Console.WriteLine("\n=====================");
        worker1.doWork();   // Result: "Worker W1 is turned ON"
        worker2.doWork();   // Result: "Worker W2 is turned OFF"

        Settings.setting1 = false;
        Settings.setting2 = true;

        Console.WriteLine("\n=====================");
        worker1.doWork();   // Result: "Worker W1 is turned OFF"
        worker2.doWork();   // Result: "Worker W2 is turned ON"

    }
}

推荐阅读