C# 一个列表中的不同类对象

Posted

技术标签:

【中文标题】C# 一个列表中的不同类对象【英文标题】:C# Different class objects in one list 【发布时间】:2012-12-03 16:15:47 【问题描述】:

我现在已经四处寻找解决这个问题的方法。我找到了几种可以解决它的方法,但老实说,我没有意识到哪些方法会被认为是“正确的”C# 或 OOP 解决方法。我的目标不仅是解决问题,而且是制定一套好的代码标准,我相当确定有一个标准的方法来处理这个问题。

假设我有 2 种类型的打印机硬件,它们各自的类和通信方式:PrinterType1、PrinterType2。

如果需要,我还希望以后能够添加另一种类型。抽象的一步,它们有很多共同点。作为示例,应该可以向它们中的每一个发送一个字符串。它们都有共同的变量和每个类独有的变量。 (例如,一个通过 COM 端口通信并具有这样的对象,而另一个通过 TCP 通信并具有这样的对象)。

然而,我只想实现所有这些打印机的列表,并且能够通过列表并在所有打印机上执行“发送(字符串消息)”,无论类型如何。我还想访问两个对象都相同的变量,例如“PrinterList[0].Name”,但是我也想在某些地方访问特定于对象本身的数据(例如在为一个对象设置 COM 端口名称而为另一个对象设置 IP/端口号的应用程序。

所以,简而言之:

共同点:

姓名 发送()

特定于 PrinterType1:

端口

特定于 PrinterType2:

IP

例如,我希望对所有对象执行 Send(),而不管对象的类型和存在的对象数量。

我已经阅读了多态性、泛型、接口等方面的内容,但我想知道在我看来基本的问题通常如何在 C#(和/或一般的 OOP)中处理。

我确实尝试过创建一个基类,但对我来说似乎不太合适。例如,我在基类本身中没有使用“字符串发送(字符串消息)”函数。那么,当我一开始就永远不会使用基类中的函数时,为什么还要在派生类中定义一个需要重写的函数呢?

我真的很感谢任何答案。这里的人似乎知识渊博,这个地方早些时候为我提供了许多解决方案。现在我终于有了一个可以回答和投票的帐户。

编辑:

另外解释一下,我还希望能够访问实际打印机类型的对象。例如 PrinterType1 中的 Port 变量,它是一个 SerialPort 对象。我想像这样访问它: PrinterList[0].Port.Open()

并可以访问底层端口的全部功能。同时,我想调用对不同对象以相同方式工作的通用函数(但具有不同的实现):

foreach (printer in Printers)
    printer.Send(message)

【问题讨论】:

我建议,无论您将针对这种特定情况使用哪种解决方案,您都应该选择一本关于 OOP 基础知识的好书。一本好书也会提供示例,我相信您会看到何时以及如何使用您选择的语言的每个功能。 +1。因为想要开发一套好的代码标准。 【参考方案1】:

使用接口的伪示例。

public interface IPrinter

   void Send();
   string Name  get; 


public class PrinterType1 : IPrinter

  public void Send()  /* send logic here */ 
  public string Name  get  return "PrinterType1";  


public class PrinterType2 : IPrinter

  public void Send()  /* send logic here */ 
  public string Name  get  return "Printertype2";  

  public string IP  get  return "10.1.1.1";  



// ...
// then to use it
var printers = new List<IPrinter>();

printers.Add(new PrinterType1());
printers.Add(new PrinterType2());

foreach(var p in printers)

  p.Send();

  var p2 = p as PrinterType2;

  if(p2 != null) // it's a PrinterType2... cast succeeded
    Console.WriteLine(p2.IP);

【讨论】:

感谢您提供非常好的和快速的建议。假设在 PrinterType2 中定义的 IP 变量是我想要编辑的 SerialPort 端口对象,我可以直接访问它吗? Port.Dispose()、Port.Name()、Port.Open() 等 接口只公开它声明的方法/属性。如果您有一组 IPrinter 对象,则必须确定特定实例是否实际上是 PrinterType2 的实例,然后对其进行适当的转换。 (这可以使用 is isas 运算符来完成。) 所以,如果一个类有一个 Port 对象而一个没有,我用 2 个对象填充 List:一个 PrinterType1 和一个 PrinterType2。其中只有一个具有“端口”对象。我怎样才能访问它?我很可能在这里遗漏了一些东西,但是在上面的代码中,我看不到我如何访问仅存在于两个类之一中的对象。您是说我需要检查列表成员的类型,将其转换为实际的类型(或者当我将其添加到列表时),然后从那里访问和编辑实际的底层对象? 您可以使用 is 运算符来确定对象是否属于特定的具体类。所以在例子的 foreach 循环中,你可以写 if(p is PrinterType2)DoSomething(); 同样,你可以使用 as 将对象转换为类型 PrinterType2,例如PrinterType2 p2 = p as PrinterType2 需要注意的是,如果 p 不属于 PrinterType2(或子类),则 p2 将为 null。 修改了我的答案以添加特定类型的转换来解释 @ThatBlairGuy 的建议【参考方案2】:

创建一个包含“常用”方法的接口(例如IPrinterType)并改用此接口。

【讨论】:

感谢您的回答。我已经研究了一些接口,但从我读过的内容来看,你不能以这种方式使用变量。因此,我必须将所有变量改为属性,这是我不喜欢的。这是一种解决方案。【参考方案3】:

您正在寻找的是一个抽象基类,如下所示:

abstract class Printer

    public string Name  get; set; 
    public abstract string Send(string Message);

然后您从该类继承并根据需要实现您的 Send() 函数。

您也可以在此处使用接口。不同之处在于接口只能指定继承者必须实现的属性、方法和事件——它本身不实现任何代码。您使用哪个取决于最适合您的应用程序的内容。你很可能会同时做这两个(创建一个实现接口的抽象类)。

【讨论】:

【参考方案4】:

对于“例如我在基类本身中没有使用“字符串发送(字符串消息)”函数的具体问题。那么为什么我要在那里定义一个需要在派生类中重写的函数呢?一开始就不会使用基类中的函数吗?”

确实没必要在基类中实现。

如果你的基类是一个抽象类,你可以简单地声明它,然后让具体的类来实现它。

如果您不想提供任何具体的实现,那么最好使用一个所有具体类都必须实现的接口来代替抽象类。

【讨论】:

【参考方案5】:

您所描述的几乎就是设计的接口。将所有通用属性/方法放入其中并隐藏具体实现。我仍然建议有一个基本的Printer 类,因为显然会有类似的代码可以共享。

当涉及到您提到的更明确的属性时,例如端口/IP,你必须知道你正在处理什么类型。此时,您可以将其转换为正确的类型。

【讨论】:

是的,正是那些更明确的属性,我在某个地方安装时遇到了最大的麻烦。我想访问一个仅存在于一个派生类中的对象(例如 SerialPort)。我想从基类访问它,因为 List 是用该类型定义的。 @jeah_wicer 所以在这种情况下,您必须将其转换为特定的派生类型,例如var castedObj = this as DerivedType; if (castedObj != null) ... .

以上是关于C# 一个列表中的不同类对象的主要内容,如果未能解决你的问题,请参考以下文章

从 Swift 中的不同类访问 ViewController 中的对象

c++ 在一个类成员数组中存储任意数量的不同类

如何从现有对象的不同类调用方法(Obj C)

删除列表中的重复对象 (C#)

从 Python 中的不同类打印?

java - 如何检查是不是在java中的不同类中单击了按钮?