C# 为什么显式实现接口?
那么,明确实现接口的好用例到底是什么C# 为什么显式实现接口?,c#,interface,C#,Interface,那么,明确实现接口的好用例到底是什么 只是为了让使用该类的人不必在intellisense中查看所有这些方法/属性吗?如果实现两个接口,都使用相同的方法和不同的实现,那么必须显式实现 public interface IDoItFast { void Go(); } public interface IDoItSlow { void Go(); } public class JustDoIt : IDoItFast, IDoItSlow { void IDoItFast.
只是为了让使用该类的人不必在intellisense中查看所有这些方法/属性吗?如果实现两个接口,都使用相同的方法和不同的实现,那么必须显式实现
public interface IDoItFast
{
void Go();
}
public interface IDoItSlow
{
void Go();
}
public class JustDoIt : IDoItFast, IDoItSlow
{
void IDoItFast.Go()
{
}
void IDoItSlow.Go()
{
}
}
当您有两个具有相同成员名称和签名的接口,但希望根据其使用方式更改其行为时,它也很有用。(我不建议编写这样的代码):
如果您有一个内部接口,并且不想公开实现类上的成员,那么应该显式地实现它们。隐式实现必须是公共的。显式实现接口可以使公共接口更干净,也就是说,您的
文件
类可以显式实现IDisposable
,并提供一个公共方法Close()
,这对使用者来说可能比Dispose(
)更有意义
F#仅提供了明确的接口实现,因此您必须始终转换到特定接口才能访问其功能,这使得接口的使用非常明确(没有双关语)。隐藏非首选成员非常有用。例如,如果同时实现了
IComparable
和IComparable
,则最好隐藏IComparable
重载,以免给人留下可以比较不同类型对象的印象。类似地,有些接口不符合CLS,如IConvertible
,因此如果不显式实现该接口,则需要符合CLS的语言的最终用户无法使用您的对象。(如果BCL实现者不隐藏原语的IConvertible成员,这将是非常灾难性的:)
另一个有趣的注意事项是,通常使用这种构造意味着显式实现接口的结构只能通过装箱到接口类型来调用它们。您可以通过使用通用约束来解决此问题:
void SomeMethod<T>(T obj) where T:IConvertible
void SomeMethod(T obj),其中T:IConvertible
将int传递给函数时不会将其装箱。另一种有用的技术是让函数的公共方法实现返回一个比接口中指定的值更具体的值 例如,一个对象可以实现
ICloneable
,但仍然有其公共可见的Clone
方法返回自己的类型
类似地,
IAutomobileFactory
可能有一个Manufacture
方法返回一个Automobile
,但是实现IAutomobileFactory
的FordExplorer
方法可能有一个FordExplorer
(它源于汽车
).Code知道它有一个FordExplorerFactory
的代码可以在FordExplorerFactory
返回的对象上使用FordExplorerFactory
特定的属性,而只知道它有某种类型的IAutomobileFactory
的代码将其返回作为Automo>处理胆汁
明确实现接口的其他一些原因:
向后兼容性:如果ICloneable
接口更改,实现方法类成员不必更改其方法签名
cleaner code:如果从iClonable中删除克隆
方法,则会出现编译器错误,但是如果隐式实现该方法,则最终可能会出现未使用的“孤立”公共方法
强键入:
为了用一个例子来说明supercat的故事,这是我首选的示例代码,实现iclonable
显式地允许Clone()
在直接作为MyObject
实例成员调用它时强类型化:
public class MyObject : ICloneable
{
public MyObject Clone()
{
// my cloning logic;
}
object ICloneable.Clone()
{
return this.Clone();
}
}
显式实现的另一个原因是可维护性 当一个类变得“忙碌”时——是的,确实如此,我们并不都有机会重构其他团队成员的代码——然后有一个显式的实现可以清楚地表明其中有一个方法来满足接口契约
因此,它提高了代码的“可读性”。这就是我们如何创建显式接口的方法: 如果我们有两个接口,并且两个接口都有相同的方法,并且一个类继承了这两个接口,那么当我们调用一个接口方法时,编译器会混淆要调用哪个方法,所以我们可以使用显式接口来处理这个问题。 下面是我举的一个例子
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();
}
}
}
对于显式定义的接口,所有方法都是自动私有的,您不能将access modifier public授予它们。假设:
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
System.Collections.Immutable
给出了一个不同的例子,作者选择使用该技术为集合类型保留一个熟悉的API,同时删除接口中对新类型没有意义的部分
具体地说,实现了IList
,从而实现了ICollection
(允许ImmutableList
更容易与遗留代码一起使用),但void ICollection.Add(T项)
对于不可变列表没有任何意义:因为向不可变列表添加元素不能更改现有列表,不可变列表
还派生自其IImmutableList Add(T项)
可用于不可变列表
因此,在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();
公共不可变列表添加(T项)
{
//使用添加的项目创建新列表
}
IImmutableList IImmutableList.Add(T值)=>this.Add(值);
void ICollection.Add(T项)=>抛出新的NotSupportedExcepti
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();