简体   繁体   English

将C#对象更改为在运行时确定的类型

[英]change C# object to type decided at run-time

The problem 问题

I have a WinForms program that has to talk to different pieces of hardware using different connection types such as TCP, USB, etc. Using the connections entails using a common set of actions provided by VISA (such as open, read, write, close). 我有一个WinForms程序,该程序必须使用不同的连接类型(例如TCP,USB等)与不同的硬件进行通信。使用连接需要使用VISA提供的一组常见操作(例如打开,读取,写入,关闭) 。 How data is passed to these functions or any transforms that might need to be applied to the data before or after use would vary by connection type. 数据如何传递到这些功能或使用之前或之后可能需要应用于数据的任何转换将因连接类型而异。

The connections are used to connect to different pieces of hardware when some method decides that a particular hardware operation requires a type of certain connection (specified by some other data). 当某种方法确定特定的硬件操作需要某种类型的连接(由某些其他数据指定)时,这些连接用于连接到不同的硬件。

At some point in the future I might like to add more types of connections. 在将来的某个时候,我可能想添加更多类型的连接。

A user of the application can select and edit a connection part of which entails changing the connection type (ie change from using TCP to using USB). 应用程序的用户可以选择和编辑连接部分,该连接部分需要更改连接类型(即,从使用TCP更改为使用USB)。 Changing the type means different method implementations will be used to operate the physical connection. 更改类型意味着将使用不同的方法实现来操作物理连接。 It is this change of type when editing a connection that I am working on. 编辑正在处理的连接时,正是这种类型的更改。

The data related to each connection (including type data) is persisted via an external data source. 与每个连接有关的数据(包括类型数据)通过外部数据源持久保存。

My solution so far 到目前为止我的解决方案

I have an abstract class Connection with some derived types such as Tcp , Usb , etc, they have common methods and properties from the abstract class (eg Address , Open() , etc) but the implementations differ to get the different data and address formats in the correct format for the VISA interface. 我有一个抽象类Connection带有一些派生类型,例如TcpUsb等,它们具有抽象类的通用方法和属性(例如AddressOpen()等),但实现方式不同,以获取不同的数据和地址格式以VISA介面的正确格式。

The application starts by populating a List<Connection> from the source of data. 该应用程序首先从数据源填充List<Connection> On this List are objects of the types derived from Connection . 在此List上是从Connection派生的类型的对象。

To present the user with controls to allow the changing of type when one of the connections from the list is selected but still keep the usage generalised the form has RadioButton controls that are created by a method that uses reflection to find generate one object of each of the derived classes and adds the names of them to the form, with a common CheckedChanged event handler . 为用户提供选择列表中的一个连接时允许更改类型的控件,但仍保持通用的用法,该表单具有RadioButton控件,该控件由一种方法创建,该方法使用反射来查找生成每个对象的一个​​对象派生的类, 并使用通用的CheckedChanged事件处理程序将它们的名称添加到表单中。

For example: 例如:

ConnectionIEnumerable = GetObjectsDerivedFromType<Connection>();
foreach (Connection c in ConnectionIEnumerable)
{
     var rb = new RadioButton();
     rb.Name = c.ToString() + "RadioButton";
     rb.CheckedChanged += new EventHandler(CommonEventHandler);
     form1.flowLayoutPanel1.Controls.Add(rb);
}

Where I'm stuck 我被困在哪里

How can this generic handler that is used "know" what type to convert the currently selected object to? 如何使用此通用处理程序“知道”将当前选定对象转换为哪种类型? How does the RadioButton store and impart the information about a related type that should be converted to? RadioButton如何存储和传递有关应转换为相关类型的信息?

I've looked at trying this plan other ways but it always comes back to a requirement that at some point there would need to be some kind of if checking the current type to convert it, or checking the type to be converted to, thus introducing non-generality. 我看了想这个计划的其他方式,但它总是回来,在某个时候将需要某种形式的要求, if检查当前的类型转换,或检查的类型转换为,从而引入非普遍性。

I think the OOP encapsulation way of doing this would be to somehow associate type information with each RadioButton as it's created and have the types themselves define how to convert between them but I'm not sure if this is correct, or of the best way of doing this; 我认为OOP封装的方式是在创建每个RadioButton某种方式将类型信息与它们关联起来,并让类型本身定义如何在它们之间进行转换,但是我不确定这是否正确,或者是最好的方法这样做; use cast overrides, a type converter, IConvertible , etc. Such that the handler could use something like (for example only) the below, to replace the object on the List: 使用IConvertible转换,类型转换器, IConvertible等。这样处理程序可以使用以下内容(仅作为示例)来替换List上的对象:

    currentObject.ConvertTo( (Type)( (RadioButton)sender).Tag ) );

Update: 更新:

For anyone with a similar quandary I took Patrick Hoffman's answer and saved type information to the RadioButton.Tag like so: 对于遇到类似难题的人,我接受了Patrick Hoffman的回答,并将类型信息保存到RadioButton.Tag如下所示:

rb.Tag = c.GetType()

Then used it in the handler like: 然后在处理程序中使用它,例如:

EditedConnection = (Connection)Activator.CreateInstance((Type)((RadioButton)sender).Tag);

How can this generic handler that is used "know" what type to convert the currently selected object to? 如何使用此通用处理程序“知道”将当前选定对象转换为哪种类型?

It shouldn't need to know that. 它不需要知道这一点。 If your program solely depends on the abstract base class, the only think you need to do is instantiate the type once, and use the base class throughout your program. 如果您的程序仅依赖于抽象基类,则您唯一需要做的就是一次实例化类型,并在整个程序中使用基类。

If you need to construct an instance, Activator.CreateInstance(Type) is what you need. 如果需要构造实例,则需要Activator.CreateInstance(Type) You could retrieve the type from the reflection you did before to populate the list. 您可以从之前填充列表的反射中检索类型。

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

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