【问题标题】:C# Dynamically create class instanceC#动态创建类实例
【发布时间】:2020-05-11 00:26:30
【问题描述】:

我处于“我不知道我不知道什么”的情况,所以我不确定这是否是解决这个问题的正确方法,如果出现这种情况,我们深表歉意一样的无知。

我有一个连接到以太网控制器的程序。该程序允许用户配置连接到系统的内容并设置 I/O 通信。

每个控制器都是自己的设备,并且可能有不同的 IO,具体取决于它的型号。控制器有自己的 API。

程序将配置保存到启动时读取的 XML 配置文件。然后我需要连接到每个未知设备并建立到每个设备的连接,让我有一种方法可以在以后引用每个设备。

这是我想要实现的目标:

 using Brainboxes.IO;
 public class BrainBoxes
 {
   public string[] Devices = new string[] { "192.168.16.147", "192.168.16.148", "192.168.16.149", "192.168.16.150" };
   List<string> EDDeviceList = new List<string>();

 public BrainBoxes() // set up devices and connections to all devices connected in the constructor
 {
    foreach (string Device in Devices)
    {
        EDDevice BB400 = EDDevice.Create("192.168.16.147");
        // BB400 is a typical name but how do I make this dynamic at the same time making it
        // available for other members of the class?
        EDDeviceList.Add(BB400); // add the device to a list to refer to later in the constructor
    }
    for (int i = 0; i < EDDeviceList.Count - 1; i++) { BB400.Connect()}; // connect to each device in sequence. 
 }


    public void Outputs(int Relay)
    {
        // this would be a switch statement 

           BB400.Outputs[Relay].Value = 1;
            Thread.Sleep(75);

           BB400.Outputs[Relay].Value = 0;

    }
    ~BrainBoxes()
    {
        BB400.Disconnect();
    }
}

【问题讨论】:

    标签: c# class dynamic automation


    【解决方案1】:

    听起来您正在尝试同时做很多事情。解释你想要的:实现(同时查看你的问题、示例代码和评论)

    • 当您的应用程序启动时,您希望它自动连接到不同设备的集合
    • 运行时,用户可以连接和配置(右侧)设备
    • 确保在应用程序停止时关闭连接

    另外,您的问题相当开放,从您的第一个陈述开始,我将假设您是初学者。我知道这很枯燥,但是您将不得不查找您正在使用的硬件的文档。幸运的是,它看起来很comprehensive

    1. 您需要为您的班级指定一个更具代表性的名称。例如。 BrainboxControllerBrainboxManager 听起来,这就是它的用途。
    2. 看起来BB400 是可能的硬件设备之一,它是继承层次结构的一部分,因此您不想仅限于此
    3. 我会避免在构造函数中做大量工作,这样会更难发现问题
    4. 使用字典来存储您的设备,这样您就可以“稍后引用每个设备”
    public class BrainboxController : IDisposable
    {
        private readonly HashSet<string> _deviceIps; // potentially you can get away without having this if you call InitialiseDevices() in the constructor
    
        private Dictionary<string, EDDevice> _devices = new Dictionary<string, EDDevice>(); // possibly use IDevice<C, P> instead of EDDevice
    
        public BrainboxController(IEnumerable<string> devices)
        {
            _deviceIps = new HashSet<string>(devices);
        }
    
        public void InitialiseDevices()
        {
            foreach (string ip in _deviceIps)
                _devices.Add(ip, EDDevice.Create(ip));
        }
    
        public void AddDevice(string ip)
        {
            if (_deviceIps.Add(ip))
                _devices.Add(ip, EDDevice.Create(ip));
        }
    
        public void RemoveDevice(string ip)
        {
            if(_devices.ContainsKey(ip))
            {
                var device = _devices[ip];
                device.Disconnect();
                device.Dispose();
                _devices.Remove(ip);
                _deviceIps.Remove(ip);
            }
        }
    
        public EDDevice GetDevice(string deviceIp)
        {
            if (_devices.ContainsKey(deviceIp))
                return _devices[deviceIp];
    
            return null;
        }
    
        public string GetConfiguration(string deviceIp)
        {
            if (_devices.ContainsKey(deviceIp))
                return _devices[deviceIp].Describe(); // I'm assuming that this gets the config data
    
            return "Device not found";
        }
    
        public bool SetConfiguration(string deviceIp, string xml)
        {
            if (_devices.ContainsKey(deviceIp))
            {
                _devices[deviceIp].SendCommand(xml); // I'm assuming this is how the config data is set
                return true;
            }
    
            // log device not found
            return false;
        }
    
        public IOList<IOLine> GetOutputs(string deviceIp, int relay)
        {
            if (_devices.ContainsKey(deviceIp))
                return _devices[deviceIp].Outputs[relay];
    
            // log device not found
            return new IOList<IOLine>();
    
        }
    
        public void Dispose()
        {
            foreach(var device in _devices.Values)
            {
                device.Disconnect();
                device.Dispose();
            }
        }
    }
    

    严格来说,如果您遵循单一职责原则,则此类应该只是管理您的设备及其连接。方法GetConfiguration()SetConfiguration()GetOutputs() 仅作为示例显示,实际上应该存在于其他地方。

    您的调用代码可能如下所示(没有依赖注入):

    var deviceAddresses = new[] { "192.168.16.147", "192.168.16.148", "192.168.16.149", "192.168.16.150" };
    var controller = new BrainboxController(deviceAddresses);
    controller.InitialiseDevices();
    var currentDevice = controller.GetDevice("192.168.16.147");
    // do something with currentDevice
    

    最后,无论你想用你的Outputs 方法做什么,它看起来像业务逻辑,它也应该存在于其他地方。

    【讨论】:

    • 非常感谢您。这对我真的很有帮助。我看过之前提到的字典,但并没有真正理解它们的用途。我的背景是机械工程师,所以我主要是自学代码。您的详细回复非常有帮助,再次感谢您。
    • 您可以遍历实现IEnumerable 接口的任何类型并匹配字段(如“ID”)。 Dictionary 数据结构针对快速查找进行了优化,但它也提供了一种更易读的方式来获取代码中的值。
    猜你喜欢
    • 2015-12-17
    • 1970-01-01
    • 1970-01-01
    • 2020-06-22
    • 1970-01-01
    • 1970-01-01
    • 2017-04-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多