MJ2507
MJ2507

Reputation: 113

C# Dynamically create class instance

I am in a situation where "I don't know what I don't know" so I am unsure if this is even the correct way of approaching this problem, apologies if this comes off as plain ignorant.

I have a program which connects to Ethernet controllers. The program allows users to configure what is connected to the system and set up I/O communication.

Each controller is its own device, and may have different IO depending on what model it is. Controllers have their own API.

The program saves the configuration to an XML config file which is read at startup. I need to then connect to each unknown device and set up a connection to each, leaving me with a method of referring to each device at a later time.

Here is what I am trying to achieve:

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

Upvotes: 0

Views: 111

Answers (1)

user1007074
user1007074

Reputation: 2596

It sounds like you're trying to do quite a few things at once. To paraphrase what you want: to achieve (looking at both your question, your sample code and your comment)

  • When your application starts, you want it to connect to a collection of different devices automatically
  • When running, users can connect to and configure (the right) device
  • Ensure that connections are closed when the application stops

Also your question is rather open ended and from your first statement, I'm going to assume that you're a beginner. I know that it's quite dry, but you are going to have to look up the documentation for the hardware you're using. Luckily, it looks quite comprehensive

  1. You need to give your class a more representative name. E.g. BrainboxController or BrainboxManager as, by the sounds of it, that is what it's for.
  2. Looks like BB400 is one of the possible hardware devices, it is part of an inheritance hierarchy, so you don't want to restrict yourself to just that
  3. I would avoid doing a lot of work in the constructor, it makes it harder to find problems
  4. Use a dictionary to store your devices, that's how you'll "refer to each device at a later time"
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();
        }
    }
}

Strictly speaking, if you follow the single responsibility principle, this class should just be managing your devices and their connections. The methods GetConfiguration(), SetConfiguration() and GetOutputs() are shown as examples and really should live somewhere else.

Your calling code could be look like this (without dependency injection):

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

Finally, whatever it is you're trying to do with your Outputs method, that looks like business logic and this also should live somewhere else.

Upvotes: 1

Related Questions