为什么要显式实现接口?

发布于 2025-01-18 18:31:54 字数 69 浏览 4 评论 0 原文

那么,显式实现接口的良好用例到底是什么?

仅仅是为了让使用该类的人不必查看智能感知中的所有这些方法/属性吗?

So, what exactly is a good use case for implementing an interface explicitly?

Is it only so that people using the class don't have to look at all those methods/properties in intellisense?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

你又不是我 2025-01-25 18:31:54

如果您实现两个使用相同方法和不同实现的接口,则必须明确实现。

public interface IDoItFast
{
    void Go();
}
public interface IDoItSlow
{
    void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
    void IDoItFast.Go()
    {
    }

    void IDoItSlow.Go()
    {
    }
}

If you implement two interfaces, both with the same method and different implementations, then you have to implement explicitly.

public interface IDoItFast
{
    void Go();
}
public interface IDoItSlow
{
    void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
    void IDoItFast.Go()
    {
    }

    void IDoItSlow.Go()
    {
    }
}
夜雨飘雪 2025-01-25 18:31:54

隐藏非首选成员很有用。例如,如果您同时实现 IComparableIComparable,那么隐藏 IComparable 重载通常会更好,以免给人这样的印象:您可以比较不同类型的对象。同样,某些接口不符合 CLS,例如 IConvertible,因此,如果您没有显式实现该接口,则需要 CLS 合规性的语言的最终用户将无法使用您的对象。 (如果 BCL 实现者没有隐藏原语的 IConvertible 成员,这将是非常灾难性的:))

另一个有趣的注意事项是,通常使用这样的构造意味着显式实现接口的结构只能通过装箱到接口类型来调用它们。您可以通过使用通用约束来解决此问题::

void SomeMethod<T>(T obj) where T:IConvertible

当您向 int 传递一个 int 时,不会对它进行装箱。

It's useful to hide the non-preferred member. For instance, if you implement both IComparable<T> and IComparable it is usually nicer to hide the IComparable overload to not give people the impression that you can compare objects of different types. Similarly, some interfaces are not CLS-compliant, like IConvertible, so if you don't explicitly implement the interface, end users of languages that require CLS compliance cannot use your object. (Which would be very disastrous if the BCL implementers did not hide the IConvertible members of the primitives :))

Another interesting note is that normally using such a construct means that struct that explicitly implement an interface can only invoke them by boxing to the interface type. You can get around this by using generic constraints::

void SomeMethod<T>(T obj) where T:IConvertible

Will not box an int when you pass one to it.

作死小能手 2025-01-25 18:31:54

Some additional reasons to implement an interface explicitly:

backwards compatibility: In case the ICloneable interface changes, implementing method class members don't have to change their method signatures.

清洁器代码:如果 clone 方法从iClonable中删除,则将出现编译器错误,但是,如果您隐含地实现该方法,则可以最终以未使用的“孤儿”公共方法最终出现

强键
为了用一个示例来说明Supercat的故事,这将是我首选的示例代码,实现 iClonable 明确允许 clone()直接将其直接称为 > MyObject 实例成员:

public class MyObject : ICloneable
{
  public MyObject Clone()
  {
    // my cloning logic;  
  }

  object ICloneable.Clone()
  {
    return this.Clone();
  }
}

Some additional reasons to implement an interface explicitly:

backwards compatibility: In case the ICloneable interface changes, implementing method class members don't have to change their method signatures.

cleaner code: there will be a compiler error if the Clone method is removed from ICloneable, however if you implement the method implicitly you can end up with unused 'orphaned' public methods

strong typing:
To illustrate supercat's story with an example, this would be my preferred sample code, implementing ICloneable explicitly allows Clone() to be strongly typed when you call it directly as a MyObject instance member:

public class MyObject : ICloneable
{
  public MyObject Clone()
  {
    // my cloning logic;  
  }

  object ICloneable.Clone()
  {
    return this.Clone();
  }
}
抚笙 2025-01-25 18:31:54

另一个有用的技术是,使函数的公共实现方法返回一个比接口中指定的值更具体的值。

例如,一个对象可以实现 ICLONABLE ,但仍然具有公开可见的 clone 方法返回自己的类型。

同样, iautomobileFactory 可能具有制造方法,该方法返回 automobile > iautomobilefactory ,可能具有其制造方法返回 fordexplorer (它源自 automobile )。代码知道它具有 fordexplorerFactory 可以使用 fordexplorer - 特定的属性在由 fordexplorerFactory返回的对象上仅仅知道它具有某种类型的 iautomobilefactory 只会以 automobile 来处理其返回。

Another useful technique is to have a function's public implementation of a method return a value which is more specific than specified in an interface.

For example, an object can implement ICloneable, but still have its publicly-visible Clone method return its own type.

Likewise, an IAutomobileFactory might have a Manufacture method which returns an Automobile, but a FordExplorerFactory, which implements IAutomobileFactory, might have its Manufacture method return a FordExplorer (which derives from Automobile). Code which knows that it has a FordExplorerFactory could use FordExplorer-specific properties on an object returned by a FordExplorerFactory without having to typecast, while code which merely knew that it had some type of IAutomobileFactory would simply deal with its return as an Automobile.

扎心 2025-01-25 18:31:54

当您有两个具有相同成员名称和签名的接口时,它也很有用,但是希望根据其使用方式更改其行为。 (我不建议这样写这样的代码):

interface Cat
{
    string Name {get;}
}

interface Dog
{
    string Name{get;}
}

public class Animal : Cat, Dog
{
    string Cat.Name
    {
        get
        {
            return "Cat";
        }
    }

    string Dog.Name
    {
        get
        {
            return "Dog";
        }
    }
}
static void Main(string[] args)
{
    Animal animal = new Animal();
    Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
    Dog dog = animal;
    Console.WriteLine(cat.Name); //Prints Cat
    Console.WriteLine(dog.Name); //Prints Dog
}

It's also useful when you have two interfaces with the same member name and signature, but want to change the behavior of it depending how it's used. (I don't recommend writing code like this):

interface Cat
{
    string Name {get;}
}

interface Dog
{
    string Name{get;}
}

public class Animal : Cat, Dog
{
    string Cat.Name
    {
        get
        {
            return "Cat";
        }
    }

    string Dog.Name
    {
        get
        {
            return "Dog";
        }
    }
}
static void Main(string[] args)
{
    Animal animal = new Animal();
    Cat cat = animal; //Note the use of the same instance of Animal. All we are doing is picking which interface implementation we want to use.
    Dog dog = animal;
    Console.WriteLine(cat.Name); //Prints Cat
    Console.WriteLine(dog.Name); //Prints Dog
}
勿挽旧人 2025-01-25 18:31:54

它可以使公共接口清洁器明确实现接口,即您的文件类可能实现 idisposable 明确提供公共方法 collect> collect()>对于消费者而言,这可能比处置()更有意义。

f#唯一的提供明确的接口实现,因此您始终必须施放特定接口才能访问其功能,这使得非常明确(不打算)使用该接口。

It can keep the public interface cleaner to explicitly implement an interface, i.e. your File class might implement IDisposable explicitly and provide a public method Close() which might make more sense to a consumer than Dispose().

F# only offers explicit interface implementation so you always have to cast to the particular interface to access its functionality, which makes for a very explicit (no pun intended) use of the interface.

攒眉千度 2025-01-25 18:31:54

如果您具有内部接口,并且不想公开实现课程成员,则可以明确实施它们。隐性实现必须公开。

If you have an internal interface and you don't want to implement the members on your class publicly, you would implement them explicitly. Implicit implementations are required to be public.

灼疼热情 2025-01-25 18:31:54

显式实现的另一个原因是为了可维护性。

当一个类变得“忙碌”时——是的,这种情况发生了,我们并不都有能力重构其他团队成员的代码——然后有一个显式的实现可以清楚地表明那里有一个方法来满足接口契约。

所以它提高了代码的“可读性”。

Another reason for explicit implementation is for maintainability.

When a class gets "busy"--yes it happens, we don't all have the luxury of refactoring other team members' code--then having an explicit implementation makes it clear that a method is in there to satisfy an interface contract.

So it improves the code's "readability".

守望孤独 2025-01-25 18:31:54

System.Collections.Immutable 给出了一个不同的示例,其中作者选择使用该技术为集合类型保留熟悉的 API,同时删除接口中对其没有任何意义的部分。新类型。

具体来说, ImmutableList 实现 IList ,因此 ICollection (为了允许 ImmutableList 更轻松地与旧代码一起使用),但 void ICollection.Add(T item) 对于 ImmutableList 没有意义:因为向不可变列表添加元素不得更改现有列表, ImmutableList 也源自 IImmutableListIImmutableList Add(T item) 可用于不可变列表。

因此,在 Add 的情况下,ImmutableList 中的实现最终如下所示:

public ImmutableList<T> Add(T item)
{
    // Create a new list with the added item
}

IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);

void ICollection<T>.Add(T item) => throw new NotSupportedException();

int IList.Add(object value) => throw new NotSupportedException();

A different example is given by System.Collections.Immutable, in which the authors opted to use the technique to preserve a familiar API for collection types while scraping away the parts of the interface that carry no meaning for their new types.

Concretely, ImmutableList<T> implements IList<T> and thus ICollection<T> (in order to allow ImmutableList<T> to be used more easily with legacy code), yet void ICollection<T>.Add(T item) makes no sense for an ImmutableList<T>: since adding an element to an immutable list must not change the existing list, ImmutableList<T> also derives from IImmutableList<T> whose IImmutableList<T> Add(T item) can be used for immutable lists.

Thus in the case of Add, the implementations in ImmutableList<T> end up looking as follows:

public ImmutableList<T> Add(T item)
{
    // Create a new list with the added item
}

IImmutableList<T> IImmutableList<T>.Add(T value) => this.Add(value);

void ICollection<T>.Add(T item) => throw new NotSupportedException();

int IList.Add(object value) => throw new NotSupportedException();
无敌元气妹 2025-01-25 18:31:54

在显式定义的接口的情况下,所有方法自动都是私有的,您不能将访问修饰符授予它们公共。认为:

interface Iphone{

   void Money();

}

interface Ipen{

   void Price();
}


class Demo : Iphone, Ipen{

  void Iphone.Money(){    //it is private you can't give public               

      Console.WriteLine("You have no money");
  }

  void Ipen.Price(){    //it is private you can't give public

      Console.WriteLine("You have to paid 3$");
  }

}


// So you have to cast to call the method


    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();

            Iphone i1 = (Iphone)d;

            i1.Money();

            ((Ipen)i1).Price();

            Console.ReadKey();
        }
    }

  // You can't call methods by direct class object

In case of explicitly defined interfaces, all methods are automatically private, you can't give access modifier public to them. Suppose:

interface Iphone{

   void Money();

}

interface Ipen{

   void Price();
}


class Demo : Iphone, Ipen{

  void Iphone.Money(){    //it is private you can't give public               

      Console.WriteLine("You have no money");
  }

  void Ipen.Price(){    //it is private you can't give public

      Console.WriteLine("You have to paid 3$");
  }

}


// So you have to cast to call the method


    class Program
    {
        static void Main(string[] args)
        {
            Demo d = new Demo();

            Iphone i1 = (Iphone)d;

            i1.Money();

            ((Ipen)i1).Price();

            Console.ReadKey();
        }
    }

  // You can't call methods by direct class object
梦一生花开无言 2025-01-25 18:31:54

这就是我们创建显式接口的方法:
如果我们有 2 个接口,并且两个接口都有相同的方法,并且单个类继承这 2 个接口,那么当我们调用一个接口方法时,编译器会混淆要调用哪个方法,所以我们可以使用显式接口来解决这个问题。
这是我在下面给出的一个例子。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace oops3
{
    interface I5
    {
        void getdata();    
    }
    interface I6
    {
        void getdata();    
    }

    class MyClass:I5,I6
    {
        void I5.getdata()
        {
           Console.WriteLine("I5 getdata called");
        }
        void I6.getdata()
        {
            Console.WriteLine("I6 getdata called");
        }
        static void Main(string[] args)
        {
            MyClass obj = new MyClass();
            ((I5)obj).getdata();                     

            Console.ReadLine();    
        }
    }
}

This is how we can create Explicit Interface:
If we have 2 interface and both the interface have the same method and a single class inherit these 2 interfaces so when we call one interface method the compiler got confused which method to be called, so we can manage this problem using Explicit Interface.
Here is one example i have given below.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace oops3
{
    interface I5
    {
        void getdata();    
    }
    interface I6
    {
        void getdata();    
    }

    class MyClass:I5,I6
    {
        void I5.getdata()
        {
           Console.WriteLine("I5 getdata called");
        }
        void I6.getdata()
        {
            Console.WriteLine("I6 getdata called");
        }
        static void Main(string[] args)
        {
            MyClass obj = new MyClass();
            ((I5)obj).getdata();                     

            Console.ReadLine();    
        }
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文