C# 定义一个接受不同参数的接口方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/238184/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 19:20:41  来源:igfitidea点击:

Define an interface method that takes different parameters

c#.netoop

提问by Enrico

My application uses measurement instruments that are connected to the PC. I want to make it possible to use similar instruments from different vendors.

我的应用程序使用连接到 PC 的测量仪器。我想让使用来自不同供应商的类似仪器成为可能。

So I defined an interface:

所以我定义了一个接口:

interface IMeasurementInterface
    {
        void Initialize();
        void Close();
    }

So far so good. Before a measurement I need to setup the instrument and this means for different instruments very different parameters. So I want to define a method that takes parameters that can have different structures:

到现在为止还挺好。在测量之前,我需要设置仪器,这意味着不同仪器的参数会有很大不同。所以我想定义一个方法,它采用可以具有不同结构的参数:

interface IMeasurementInterface
{
    void Initialize();
    void Close();
    void Setup(object Parameters);
}

I will then cast the object to whatever I need. Is this the way to go?

然后我会将对象投射到我需要的任何地方。这是要走的路吗?

回答by Andru Luvisi

That would probably work. Another option is to pass the parameters in a dictionary.

那可能会奏效。另一种选择是在字典中传递参数。

回答by Eoin Campbell

You might be better off coming up with an abstract "Parameters" class that is extended by each different instruments parameters... e.g. and then using Generics to ensure that the correct parameters are passed to the correct classes...

您最好提出一个由每个不同仪器参数扩展的抽象“参数”类……例如,然后使用泛型来确保将正确的参数传递给正确的类……

public interface IMeasurement<PARAMTYPE> where PARAMTYPE : Parameters
{
    void Init();
    void Close();
    void Setup(PARAMTYPE p);
}

public abstract class Parameters
{

}

And then for each specific Device,

然后对于每个特定的设备,

public class DeviceOne : IMeasurement<ParametersForDeviceOne>
{
    public void Init() { }
    public void Close() { }
    public void Setup(ParametersForDeviceOne p) { }
}

public class ParametersForDeviceOne : Parameters
{

}

回答by Kasper

To me it sound like the Factorypattern might be usefull, especially if your are going to unit test your app.

对我来说,工厂模式听起来可能很有用,尤其是当您要对应用程序进行单元测试时。

回答by computinglife

If you are going to deal with even more than one device type, then controller + device interface seperation, which communicates using Name vlaue pairs would be a good solution

如果您要处理不止一种设备类型,那么控制器 + 设备接口分离,使用 Name vlaue 对进行通信将是一个很好的解决方案

DECOUPLING

脱钩

Using name value pairs allows you to seperate your code into a device + controller + application code structure

使用名称值对允许您将代码分成设备 + 控制器 + 应用程序代码结构

Sample Code

示例代码

class DeviceInterface
    {
    void Initialize(IController & Controller);
    void Close();
    bool ChangeParameter(const string & Name, const string & Value); 
    bool GetParam(string & Name, string &Value );
    }

Each device implementation, when created should be created with the identification of the controller that can accept its commands and translate them into the actual device commands

每个设备实现在创建时都应该带有可以接受其命令并将其转换为实际设备命令的控制器的标识

interface IController
   {
   Initialize(DeviceSpecific & Params);
   Close();
   bool ChangeParameter(string & Name, string & Value);
   bool ChangeParams(string & Name[], string &Value []);
   }

Your user code would look something like this

您的用户代码看起来像这样

IController     objController = new MeasurementDevice(MeasureParram);

DeviceInterface MeasureDevice = new DeviceInterface(objController);

string Value;

MeasureDevice.GetParam("Temperature", Value);

if (ConvertStringToInt(Value) > 80)
     {
     MeasureDevice.ChangeParameter("Shutdown", "True");
     RaiseAlert();
     }

All that the DeviceInterface class should do is take care of passing the commands to the controller. The controller should take care of the device communication.

DeviceInterface 类应该做的就是负责将命令传递给控制器​​。控制器应负责设备通信。

Advantages of the interface seperation

接口分离的优点

Protect againt changes

防止更改

This sort of decoupling will allow you to isolate your app code from the controller. Changes in the device does not affect your user code

这种解耦将允许您将应用程序代码与控制器隔离。设备中的更改不会影响您的用户代码

Maintainability of Appliction Code

应用程序代码的可维护性

Addtionally the user code is always clean and you need bother only with the application logic. But had you defined multiple interfaces / created templates or generics with multiple types of parameter structs specific to controller, your code would have lots of device dependent junk in it which might hurt readability and create maintenance issues whenever your device / its parameters changes.

此外,用户代码总是干净的,您只需要处理应用程序逻辑。但是,如果您定义了多个接口/创建的模板或具有多种类型的特定于控制器的参数结构的泛型,您的代码中将包含大量依赖于设备的垃圾,这可能会损害可读性并在您的设备/其参数更改时产生维护问题。

Implementation ease

易于实施

You can also hive off different controller implementations into its own projects. Plus your application can also configure commands and responses in a more dynamic naure using XML files etc that can ship along with the controller classes such that your entire application becomes more dynamic in nature.

您还可以将不同的控制器实现集成到自己的项目中。此外,您的应用程序还可以使用 XML 文件等以更动态的方式配置命令和响应,这些文件可以与控制器类一起提供,从而使您的整个应用程序在本质上变得更加动态。

Real Life

现实生活

One of the latest production controller projects from the leader in that domain works in the same manner. But they use LON for the device communication.

来自该领域领导者的最新生产控制器项目之一以相同的方式工作。但是他们使用 LON 进行设备通信。

LON ?

隆?

LON protocol used in controllers (think air-conditioner / boiler / fans etc) networks use this concept to talk to various devices

控制器(例如空调/锅炉/风扇等)网络中使用的 LON 协议使用此概念与各种设备进行通信

So all that you would need to have is a single interface that can talk to your device and then sends the name value pair to it using LON. he use of a standard protocol will also allow you to talk to other devices besides your measurement instrument. There are open source implementations of LON available if your device uses LON.

因此,您所需要的只是一个可以与您的设备通信的单一接口,然后使用 LON 将名称值对发送给它。使用标准协议还可以让您与测量仪器以外的其他设备通话。如果您的设备使用 LON,则可以使用 LON 的开源实现。

If your device does not support LON then you might have to design something where the user code still works on name value pairs and an opposite interface translates your name value pairs into an equivalet corresponding cotroller struct+ and communicates to the individua device in the way the device understands .

如果您的设备不支持 LON,那么您可能必须设计一些东西,其中用户代码仍然适用于名称值对,并且相反的接口将您的名称值对转换为等效的对应控制器 struct+ 并以设备的方式与单个设备通信明白了。

Hope this comes useful.

希望这有用。

回答by Mike Minutillo

It depends on how you are going to get the parameters in the first place. If they are stored off in a database table or a config file somewhere and it's just values that need to be set then passing in a dictionary will probably do it (although you do lose type safety). If your setup processes are going to be a little more complicated then I'd consider abstracting away the setup process a little further and performing a double dispatch (pushing the cast operation into a new setup class). Like this

这首先取决于您将如何获取参数。如果它们存储在数据库表或某处的配置文件中,并且只是需要设置的值,那么传入字典可能会这样做(尽管您确实失去了类型安全性)。如果您的设置过程会更复杂一点,那么我会考虑进一步抽象化设置过程并执行双重调度(将强制转换操作推送到新的设置类中)。像这样

public interface IMeasurementInterface
{
  void Initialize();
  void Close();
  void Setup( IConfigurer config );
}

public interface IConfigurer
{
  void ApplyTo( object obj );
}

public abstract ConfigurerBase<T> : IConfigurer where T : IMeasurementInterface
{
  protected abstract void ApplyTo( T item );

  void IConfigurator.ApplyTo(object obj )
  {
    var item = obj as T;
    if( item == null )
      throw new InvalidOperationException("Configurer can't be applied to this type");
    ApplyTo(item);
  }
}

This way you aren't messing up your Measurement class hierarchy (or providing no implementation and assuming that all implementations will do what you want anyway). It also means that you can test your Setup code by passing in a fake (or Mocked) Measurement device.

这样您就不会弄乱您的 Measurement 类层次结构(或不提供任何实现并假设所有实现无论如何都会做您想要的)。这也意味着您可以通过传入一个假的(或模拟的)测量设备来测试您的设置代码。

If the setup process needs to manipulate private or protected data then you can make the concrete implementation of the IConfigurer reside inside its corresponding Measurement class.

如果设置过程需要操作私有或受保护的数据,那么您可以使 IConfigurer 的具体实现驻留在其相应的 Measurement 类中。

回答by RS Conley

I have to this for my software as I need to support many different types of motion controllers for metal cutting machines.

我的软件必须这样做,因为我需要支持许多不同类型的金属切割机运动控制器。

Your interface has the basics you need. The thing you need to remember is that you don't need to pass in a list of parameters. You pointed out each type of device could have a very different type of setup.

您的界面具有您需要的基础知识。您需要记住的是,您不需要传入参数列表。您指出每种类型的设备可能具有非常不同的设置类型。

The way I do it is as follows

我的做法如下

interface IMeasurementInterface
{
    void Initialize();
    void Close();
    void Setup();
    void Read (FileReader as <whatever read file object you are using>)
    void Store (FileReader as <whatever read file object you are using>)
    string Name();
}

Setup calls a dialog box created in the assembly of the IMeasurementDevice. The dialog is NOT Visible outside of the assembly.

安装程序调用在 IMeasurementDevice 的程序集中创建的对话框。该对话框在程序集外部不可见。

Now I know some object oriented or MVC purist may object to this. However I feel the concept of hiding the internals of a specific Measurement class outweighs strict adherence to the MVC architecture.

现在我知道一些面向对象或 MVC 纯粹主义者可能会反对这一点。但是,我觉得隐藏特定 Measurement 类的内部结构的概念比严格遵守 MVC 架构更重要。

My general philosophy is that trival dialog are implemented in the same assembly provided that it is private to the assembly and called by an object implementing on the standard interfaces that I setup. Again the reason for this is I find hiding the internals to be more valuable than trying to implement all the dialogs in the top level assembly.

我的一般理念是,琐碎的对话在同一个程序集中实现,前提是它对程序集是私有的,并且由在我设置的标准接口上实现的对象调用。再次这样做的原因是我发现隐藏内部比尝试在顶级程序集中实现所有对话框更有价值。

By specifying a Read Method and a Store method you eliminate the need to expose the internal setup parameters for saving. All you need is to pass whatever type of file storage object you are using to save your setup parameters.

通过指定读取方法和存储方法,您无需公开内部设置参数以进行保存。您所需要的只是传递您用来保存设置参数的任何类型的文件存储对象。

Finally like another poster stated you need to setup a Factory Class in your assembly containing all your measurement devices. During your setup you need to instantiate this class and retrieve the list of supported measurement devices.

最后,就像另一张海报所说的那样,您需要在包含所有测量设备的程序集中设置一个工厂类。在设置期间,您需要实例化此类并检索支持的测量设备列表。

The way I do it is my factory class retrieves a list of motion controllers. This list is part of a master class where all the setup classes are stored. When I read my setup files I get the controllers that are actually being used. I retrieve those classes out of the list and place them in another list that is actually used during the cutting process.

我这样做的方式是我的工厂类检索运动控制器列表。此列表是存储所有设置类的主类的一部分。当我阅读我的设置文件时,我得到了实际使用的控制器。我从列表中检索这些类,并将它们放在切割过程中实际使用的另一个列表中。

The reason I do it this way is that when the user is setting up motion controllers he need to be able to pick from a list of ALL the available controls in order to tell the software which one he has. I find it more responsive to keep a list of available controllers around.

我这样做的原因是当用户设置运动控制器时,他需要能够从所有可用控件的列表中进行选择,以便告诉软件他拥有哪个控件。我发现保留可用控制器列表更灵敏。