【问题标题】:Is there any way an interface can cause different behavior?接口有什么方法可以导致不同的行为?
【发布时间】:2012-11-23 18:57:22
【问题描述】:

假设我有以下代码:

class Foo: IFoo {
    public string fooProp { get; set; }
}

interface IFoo {
    string fooProp {get; set; }
}

这两者之间是否可能存在不同的行为:

Foo x = new Foo();
someMethod(x);

和:

IFoo x = new Foo();
someMethod(x);

?

【问题讨论】:

  • 鉴于您上面显示的示例,不。假设someMethod 的签名采用IFoo
  • 用接口应该是不可能的,不。 (与抽象/虚拟类/成员和其他此类继承概念相反。)您是否注意到表明它可以不同的行为?还是这主要是一种无聊的好奇心?
  • 嗯,我看到的问题更复杂,但我认为本质上唯一的区别是它是由类声明还是由接口声明,并且它的行为不同。
  • 如果你有 someMethod 的两个重载版本,一个是 Foo,另一个是 IFoo,那么你可以让它做两件不同的事情。
  • 您能否提供一个简短但完整的问题示例?你给出的例子没有明显的区别,如果我们有一个更完整的例子,我相信有人可以很容易地发现发生了什么。

标签: c#


【解决方案1】:

我认为可能会有所不同。如果有人使用了糟糕的编程风格,即:

public void someMethod(IFoo f)
{
    if (f is Foo)
    {
        Foo f1 = (Foo)f;
        //Do smth with unique Foo members
    }
    //Do anything with IFoo members
}

【讨论】:

  • 请记住,这完全不是一个坏习惯。例如,LINQ 一直这样做。当具体类型实际上是ICollection 时,它可以通过这样做更有效地执行许多操作,而不会改变最终结果。它还使它对调用者不可见(除了更快)。
  • 是的,当然,如果有必要,那么可以使用。最重要的是要有右手/头。)
  • 但这不是必须的,这实际上是我的观点。这纯粹是性能优化。重要的一点是它对方法的用户是不可见的,并且编写者/维护者愿意为更高的内部复杂性和维护成本付出代价,以换取它提供的任何优势。
【解决方案2】:

如果你明确地实现IFoo是可能的:

public class Foo : IFoo
{
    public string Prop
    {
        get { return "Hello Foo"; }
    }

    string IFoo.Prop
    {
        get { return "Hello IFoo"; }
    }
}

public static void SomeMethod<T>(T foo) where T : IFoo
{
    var prop = typeof(T).GetProperty("Prop");
    Console.WriteLine(prop.GetValue(foo));
}

【讨论】:

    【解决方案3】:

    您可以在 Foo 中明确实现接口。

    class Foo: IFoo {
        private string _fooprop;
        private string _ifooprop;
    
        public string fooProp       
        {
            get {return "IFoo";}
            set {_fooprop=value;}
        }
        string IFoo.fooProp 
        {
            get {return "Foo";}
            set {_ifooprop=value;}
        }
    }
    
    interface IFoo {
        string fooProp {get; set; }
    }
    

    有了这个,你将拥有:

    IFoo foo1=new Foo();
    Foo foo2=new Foo();
    
    Console.WriteLine(foo1.fooProp); // Foo
    Console.WriteLine(foo2.fooProp); // iFoo
    

    【讨论】:

      【解决方案4】:

      不同的行为可以是,但在someMethod内部。

      说你有

      class Foo: IFoo {
          public fooProp { get; set; }
      }
      
      interface IFoo {
          fooProp {get; set; }
          myCustomProp {get;set}
      }
      

      如果你有

      public void someMethod(Foo _foo){
           _foo.myCustomProp; //CAN DO THIS, AS YOUR TYPE IS _FOO_
      }
      

      如果方法的参数被定义为这样,这是不可能的。

      public void someMethod(IFoo _foo){
           _foo.myCustomProp; //NO SUCH METHOD INFO
      }
      

      除非你不施放。所以不同之处在于 decaring IFoo,decalre 通用访问参数,但在数据访问方面获得的“潜力”较少,但在架构中的类型抽象方面获得巨大潜力。

      所以区别只在于架构和程序工作流程。

      【讨论】:

      • 这个例子是一个编译一个不是......我的情况是编译和运行,但给出不同的行为
      • @JoelFan:所以你需要抽象,在这种情况下。只需像参数一样使用IFoo
      【解决方案5】:

      如果你有两个接口并且每个接口都有一个通用的方法名,那么实现类可以不同地实现相同的方法。这取决于方法是如何被调用的——通过接口与否以及通过哪个接口。

      类似问题请看这里:

      Inheritance from multiple interfaces with the same method name

      【讨论】:

        【解决方案6】:

        是的,如果someMethodIFooFoo 有不同的重载,则会有所不同。

        public void someMethod(Foo f)
        {
            // Overload 1
        }
        
        public void someMethod(IFoo f)
        {
            // Overload 2
        }
        
        Foo x = new Foo();
        someMethod(x); // Matches overload 1
        IFoo x = new Foo();
        someMethod(x); // Matches overload 2
        

        【讨论】:

        • 如果所讨论的方法是扩展方法,这可能会变得更加微妙,从而看起来行为是在对象本身上。
        【解决方案7】:

        永远不会有任何区别。

        请记住,接口是合同。通过从IFoo 派生Foo,您正在实施该合同

        在这两种情况下,因为Foo IFoo 并遵守合同,所以行为将始终相同。

        当然, Foo 是如何实现该合约的,谁都猜不透。但是接口的签名也遵守了合同。

        【讨论】:

          【解决方案8】:

          (我不是专家)但在您的第一个场景中,您可以访问 Class Foo 中的所有内容。在第二种情况下,您将只能访问 IFoo 成员。因此,如果 Foo 有其他方法(不是接口的一部分),您将能够在第一个场景中访问它们,但在第二个场景中则不能。

          我相信使用接口名称而不是类名称只是封装数据的另一种方式,并且只提供对接口成员的访问。例如,您可以拥有 Foo 和 Bar,它们都实现了 IFoo。您可以将它们都添加到一个列表中。

          【讨论】:

          • 好的,但如果someMethod 会利用其他成员,那么如果使用该接口,它将无法编译。在我的情况下,它正在为两者编译和运行,只是给出不同的结果
          • 你没有提到 someMethod 接受什么作为参数。如果它接受 IFoo,那么两者都可以。如果它需要 Foo,则第二种情况将无法编译。
          • 我也相信你的评论有点错误。接口实现将始终在类中完成,而不是在接口中。因此,即使您传递 Foo 或 Bar,如果 someMethod 需要 IFoo,两者都应该工作并且都将使用其接口的特定实现(参考:利用其他成员)
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-01-09
          • 2020-12-31
          • 2020-06-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-06
          相关资源
          最近更新 更多