繁体   English   中英

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

[英]How to get the current value of a field or property passed to constructor, without using reflection

我有一类可以在其他地方管理的设置,还有许多需要了解与自己相关的设置的当前值的辅助类的实例。 设置可能随时更改。

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

下面的代码说明了我要完成的工作,但是当然会失败,因为在实例化worker时会复制设置的值。 在需要这些值时,我有什么选择?

我如何才能修改此代码以实现所需的行为而不会一团糟?

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();
        }
    }
}

我已经阅读了许多关于变通办法的问答,因为无法通过引用传递属性,并且有很多提示和建议,但是没有一个以任何方式回答我的问题,我可以将其转化为决定和建议。一个可行的解决方案。 我回到约翰·斯基特(John Skeet)的C#书并重新阅读,我确定答案就在那儿-但我仍然看不到它。

我知道我可以传递属性名称并使用反射来获取值。 魔术弦使我不舒服,但也许NameOf()可以使我满意。 我知道我可以创建一个名为设置的类,并编写一个函数来返回给定设置名称的值。 我了解委托可以提供帮助,但是我看到的示例似乎要求每个设置都委托一个人,我希望有一个简洁的解决方案。

我以为我可以放弃财产并使用公共领域,传递对该领域的引用,但是SO上的一些聪明人建议在与我的问题类似(但不相同)的问题上反对这种方法。

我忍不住觉得这一定是功能上必不可少的一点,并希望有一种普遍接受的方法在C#中进行处理。

您需要将引用类型传递给构造函数。 您可以为您的设置创建一个类,并使用要更新的实例。

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

如果您需要保持Settings类不变,则可以执行以下操作:

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"

    }
}

我为您编写了一个更加C#友好的示例。

我没有使用setting1和setting2,而是使用了Settings类的两个不同实例。

    public class Settings: ISettings
    {
        public bool MySetting { get; set; }
    }

在设计中添加worker3 ,需要添加setting3 使用此处显示的设计,您无需修改Settings类。

这是代码(接口部分不是必需的,但是允许以后轻松进行模拟,这是一个好习惯)

运行此代码的结果是

在此处输入图片说明

    public interface ISettings
    {
        bool MySetting { get; set; }
    }

    public class Settings: ISettings
    {
        public bool MySetting { get; set; } = true;
    }
    public class mWorker
    {
        private string wName;
        private ISettings settings;
        public mWorker(string _name, ISettings settings)
        {
            wName = _name;
            this.settings = settings;
        }
        public void doWork()
        {
            var onOff = (settings.MySetting) ? "ON" : "OFF";
            Console.WriteLine($"Worker {wName} is turned {onOff}");
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var settingsForWorker1 = new Settings() { MySetting = true };
            mWorker worker1 = new mWorker("W1", settingsForWorker1);
            var settingsForWorker2 = new Settings() { MySetting = false };
            mWorker worker2 = new mWorker("W2", settingsForWorker2);

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

            settingsForWorker1.MySetting = false;
            settingsForWorker2.MySetting = true;

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

如果将设置存储在集合中,则可以轻松地为任意数量的工作人员管理设置:

var settings = new Dictionary<string, Settings>()
{
    { "W1", new Settings() { MySetting = true } },
    { "W2", new Settings() { MySetting = false } },
    { "W3", new Settings() { MySetting = false } },
};

mWorker worker1 = new mWorker("W1", settings["W1"]);
mWorker worker2 = new mWorker("W2", settings["W2"]);

(...)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM