【问题标题】:How to create method interface with variable parameters / different method signatures?如何创建具有可变参数/不同方法签名的方法接口?
【发布时间】:2011-09-01 03:40:55
【问题描述】:

我正在尝试创建一个通用类的接口,但实现类可以有不同的参数。

例如

public interface IViewModel
{
    //...
    void ResetReferences(); 
}

// and then, in my class implementations, something like this:
public class LocationViewModel : IViewModel
{
    public void ResetReferences(List<StateProvinces> stateProvinces) //...
}

public class ProductViewModel : IViewModel
{
    public void ResetReferences(List<Color> colors, List<Size> sizes) //...
}

所以请注意,我想标准化 ResetReferences 命名约定。我很确定我不能这样做,但是有没有可行的设计模式?例如在我的界面中,如下所示?

// variable parameters
void ResetReferences(params object[] list); 

但是我该如何进行类型检查或让它调用我想要的实际方法签名等?

也许接口是错误的使用方式?也许只是一个基类和一些编码约定?

谢谢,

【问题讨论】:

    标签: c# .net interface methods


    【解决方案1】:

    用实现相关接口的对象替换您的 args 列表:

    public interface IViewModel
    {
        //...
        void ResetReferences(IResetValues vals); 
    }
    

    我应该补充一点,IMO,ResetReferences() 不应该接受参数......它应该重置为特定于实现您的接口的各个类型的默认值......“重置”是这个词对我来说意味着“恢复到初始状态”...添加 args 意味着您可以控制它。

    【讨论】:

    • 我喜欢你的方法,谢谢。顺便说一句,我已将该方法重命名为“SetReferences”:)
    • @Raymond:如果您喜欢这个答案,请点赞,并给 JeffSahol 10 更多声望点。人们欣赏“谢谢”评论,但在追求声誉的过程中,评论无济于事。
    【解决方案2】:

    您必须在接口中同时拥有这两种方法(并且让一个不正确的方法对实例抛出不受支持的异常),或者让接口从其他两个接口继承以达到相同的效果。

    接口定义是整个签名。

    也可以将对象作为参数传递(可能从 ParameterProvider 基类派生),以便对象封装动态特性并仍然允许接口是静态的。但那一点你基本上是在围绕类型系统工作。

    【讨论】:

      【解决方案3】:

      如果参数可以不同,那么它就不是一个真正的通用接口。这么说吧:调用者需要知道实现类吗?如果是这样,您就失去了接口的松散耦合优势。

      一种选择是将参数封装到另一种类型中,并使该类在该类型上通用。例如:

      public interface IViewModel<T>
      {
          void ResetReferences(T data);
      }
      

      然后您将List&lt;Color&gt; colors, List&lt;Size&gt; sizes 封装为一种类型,并可能将List&lt;StateProvinces&gt; stateProvinces 放入另一种类型中。

      虽然有点尴尬……

      【讨论】:

      • “虽然有点尴尬……” 解决这个问题最理想的方法是什么?
      • @b1nary.atr0phy:理想情况下“不要让自己陷入这种情况”。鉴于信息有限,我已经给出了我能给出的最佳答案——它非常敏感。
      • 我不认为你可以在ResetReferences(T data)的实现中做任何通用的事情,T没有通用的接口可以操作。
      • @zoujyjs:但实现不必是通用的——它可以特定于一种类型。这不是通用的方法 - 它是接口。所以有人可以实现IViewModel&lt;Foo&gt;,他们只需要知道如何处理 Foo。
      【解决方案4】:

      你需要实现接口方法,但你仍然可以做你想做的事

      public class LocationViewModel : IViewModel
      {
          public void ResetReferences(List<StateProvinces> stateProvinces) // ...
      
          void IViewModel.ResetReferences() // ...
      }
      

      【讨论】:

      • 这不是一个好的解决方案,因为它违反了SOLID原则的接口隔离原则(ISP):一个类不得必须实现特定类不需要的任何接口元素!跨度>
      【解决方案5】:

      接口的目的是让客户端代码知道接口并忽略实现。如果您的实现在调用时需要特殊处理,则客户端代码需要知道它正在调用什么实现,然后接口的整个目的就丢失了。

      除非我完全误解了你想要完成的事情,否则你走错路了。

      【讨论】:

      • 是的,我认为你是对的。我把逻辑放在错误的地方。 (这是一个 MVC 应用程序,所以我现在将 ResetReferences 放在 Controller 类而不是 ViewModel 类中)。
      • 完全正确。在实现类中隐藏功能会从interface 中带走很多价值,因为interface 并没有完全定义实现类将要做什么。
      猜你喜欢
      • 1970-01-01
      • 2013-02-02
      • 2017-07-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多