C# 为什么用相同的属性实现多个接口显示';歧义';警告
相关职位: 来自同一来源的代码:C# 为什么用相同的属性实现多个接口显示';歧义';警告,c#,interface,compiler-errors,C#,Interface,Compiler Errors,相关职位: 来自同一来源的代码: private interface IBase1 { int Percentage { get; set; } } private interface IBase2 { int Percentage { get; set; } } private interface IAllYourBase : IBase1, IBase2 { } privat
private interface IBase1
{
int Percentage { get; set; }
}
private interface IBase2
{
int Percentage { get; set; }
}
private interface IAllYourBase : IBase1, IBase2
{
}
private class AllYourBase : IAllYourBase
{
private int _percentage;
public int Percentage
{
get { return _percentage; }
set { _percentage = value; }
}
}
private void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; // Fails to compile. Ambiguity between 'Percentage' property.
}
(但没有回答我的问题——“为什么合同变得模棱两可?”)
鉴于:
接口是实现类必须遵守的契约
如果两个(或多个)接口要求相同的契约,并且一个接口将它们“向前”传递,然后类实现了这两个契约,并接受公共契约应仅作为实现类的一个契约(通过不提供显式实现)。那么
public interface IIndexPriceTable{
int TradeId{get;}
int IndexId{get;}
double Price{get;}
}
public interface ILegPositionTable{
int TradeId {get;}
int LegId {get;}
int Position {get;}
}
public interface ITradeTable {
int TradeId{get;}
int IndexId{get;}
int LegId{get;}
//others
}
public interface IJoinedTableRecord : IIndexPriceTable, ILegPositionTable, ITradeTable {
//Just to put all contracts under one interface and use it as one concrete record, having all information across different tables.
}
- 为什么我希望在我的联接表记录中有3-TradeId、2-LegId和2-IndexId
IBase1.Percentage
或IBase2.Percentage
),因为您的iallyurbase
接口紧跟这两个接口,并且它们各自都有自己的Percentage
属性
这样说:仅仅因为两个接口具有相同名称和类型的属性,并不意味着该属性在两个接口中的工作方式相同。即使公共接口继承自两个具有相同成员的接口,编译器也不能将两个看似相同的属性合并为一个,因为它们是两个不同契约的成员。我明白你的意思。我想这个编译器限制的主要好处是最好有一个,而不是没有。也就是说,有更多的伤害,那么你无意中的界面混乱将被忽略,然后受益(如果有任何)从这个奇怪的情况下,你想要这样的行为
顺便说一句,在任何现实场景中,所需的行为都会非常有用?因为接口
iallyurbase
没有声明百分比
属性本身
当您将AllYourBase
的实例分配给iallyurbase
变量时,编译器需要输出对IBase1.Percentage
或IBase2.Percentage
的调用:
callvirt instance int32 IBase1::get_Percentage()
或
它们是不同类型的不同成员,仅仅因为它们具有相同的签名并不意味着它们可以互换
在现实世界中,您可能需要更细粒度的接口来定义公共属性。如果一个接口继承了另外两个具有相似命名成员的接口,则必须应用以下两个条件之一:
IListOfDigits
,它的Add
方法将一个整数0-9追加到列表中,还有ibignNumber
,它的Add
方法将一个数字进行算术相加。还有一个接口IListoDigits代表BigNumber,它继承了这两者。给定一个名为myThing
的代表BigNumber的IListoDigits,其中包含数字“5,4,3,2”,那么myThing的效果应该是什么。添加(1)?它是否应该将myThing
更改为保持“5,4,3,2,1”(添加的数字的效果)或“5,4,3,3”(添加的IBignNumber.Add的效果)?如果执行上述任一操作,编译器将毫不费力地确定要使用哪个Add
方法。否则,如果两个方法都可以接受int
,那么它就没有线索了
顺便说一句,泛型和重载构成了一个有趣的例子。如果IFoo
具有成员void Bar(T参数)
和void Bar(U参数)
,则不能将类声明为实现IFoo
。另一方面,可以将一个类Foo
声明为实现IFoo
,然后将另一个类声明为继承自Foo
,因为即使T
和U
引用相同的类型,编译器仍将使用T
和U
解决重载问题。解决方案是使用如下新关键字再次定义属性百分比:
private interface IBase1
{
int Percentage { get; set; }
}
private interface IBase2
{
int Percentage { get; set; }
}
private interface IAllYourBase : IBase1, IBase2
{
new int Percentage { get; set; }
}
private class AllYourBase : IAllYourBase
{
private int _percentage;
public int Percentage
{
get { return _percentage; }
set { _percentage = value; }
}
}
private void Foo()
{
IAllYourBase iayb = new AllYourBase();
int percentage = iayb.Percentage; //OK
}
注意:
对接口的C#方法与对接口的C#方法非常不同。在C#中,您必须声明,类通过修改类本身来实现接口,而在C++14中,它只需要具有与接口定义相对应的方法。因此,C++中的代码比C++14中的代码具有更多的依赖关系。行int percentage=iayb.percentage
不知道它在处理AllYourBase
类,只是不管它是什么,它实现了iallyurbase
接口
因此,假设我尝试使用我的DoubleBase
类执行相同的语句:
private class DoubleBase : IAllYourBase
{
int IBase1.Percentage { get; set; } = 10;
int IBase2.Percentage { get; set; } = 20;
}
int percentage
设置为什么值?但作为
private class DoubleBase : IAllYourBase
{
int IBase1.Percentage { get; set; } = 10;
int IBase2.Percentage { get; set; } = 20;
}