Geo*_*pos 5 c# interface-implementation .net-core
我开始更深入地研究 C# 编程,并且一直在研究接口。
我了解接口的基础知识,因为它们应该是实现它们的任何类的“契约”。接口中定义的任何内容都需要在继承(不确定这是否是正确的术语)它们的任何类中实现。
因此,我向接口添加了一个属性,该属性本身就是一个接口。当尝试实现父接口时,我向我的类添加了一个属性,该类实现了父接口中的属性接口。这个解释可能有点令人困惑,所以我在下面添加了一些代码。
interface IPropertyThatIsAnInterface
{
public int X { get; set; }
}
class ClassThatImplementsIPropertyThatIsAnInterface : IPropertyThatIsAnInterface
{
public int X { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
interface IAnInterface
{
public IPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
class ClassThatImplementsIAnInterface : IAnInterface
{
public ClassThatImplementsIPropertyThatIsAnInterface InterfaceImplmentationProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
Visual Studio(在 .Net Core 3.0 [即 C# 8.0] 中)出现错误,指出我的类ClassThatImplementsIAnInterface未实现接口属性 ,public IPropertyThatIsAnInterface InterfaceProperty { get; set; }(这是一个接口属性)。这是 C# 的限制还是我对接口理解的限制?
我这样做的原因是因为我想IPropertyThatIsAnInterface为ClassThatImplementsIAnInterface我创建的每个对象实现自定义。IE
class AnotherClassThatImplementsIPropertyThatIsAnInterface : IPropertyThatIsAnInterface
{
public int X { get; set; }
public int Z { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
我可以通过执行以下操作来解决此问题
class ClassThatImplementsIAnInterface : IAnInterface
{
public IPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
但问题是,InterfaceProperty在访问该属性时,即((ClassThatImplementsIPropertyThatIsAnInterface)InterfaceProperty).Y每当我访问自定义类属性之一时,我都需要将每个调用强制转换到类定义中。这还可以,但不太好。
那么,这是 C# 的限制还是我理解的限制?
这是有效的 C#:
interface IAnInterface
{
IPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
interface IPropertyThatIsAnInterface
{
int X { get; set; }
}
class ClassThatImplementsIAnInterface : IAnInterface
{
public IPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
你可以这样做
class ClassThatImplementsIAnInterface : IAnInterface
{
public ClassThatImplementsIPropertyThatIsAnInterface InterfaceImplmentationProperty { get; set; }
public IPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
class ClassThatImplementsIPropertyThatIsAnInterface : IPropertyThatIsAnInterface
{
public int X { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
请注意,InterfaceImplmentationProperty与 无关IAnInterface。
我们可以InterfaceProperty显式地实现implement,从而隐藏它:
IPropertyThatIsAnInterface IAnInterface.InterfaceProperty { get; set; }
Run Code Online (Sandbox Code Playgroud)
然而,InterfaceProperty和InterfaceImplmentationProperty仍然是分开的。让我们委托InterfaceProperty给InterfaceImplmentationProperty:
IPropertyThatIsAnInterface IAnInterface.InterfaceProperty
{
get => InterfaceImplmentationProperty;
set => InterfaceImplmentationProperty = value; // ERROR
}
Run Code Online (Sandbox Code Playgroud)
现在,我们有一个错误。因为,您会看到, anIPropertyThatIsAnInterface不一定是 InterfaceImplmentationProperty。但是,IAnInterface我可以IPropertyThatIsAnInterface在那里设置任何承诺。
如果我们继续这条路,我们就必须颠覆预期,并抛出异常:
IPropertyThatIsAnInterface IAnInterface.InterfaceProperty
{
get => InterfaceImplmentationProperty;
set => InterfaceImplmentationProperty = (ClassThatImplementsIPropertyThatIsAnInterface)value;
}
Run Code Online (Sandbox Code Playgroud)
在这里,我添加了一个强制转换,这可能会在运行时失败。它很容易被忽视......我们可以更具表现力一点:
IPropertyThatIsAnInterface IAnInterface.InterfaceProperty
{
get => InterfaceImplmentationProperty;
set
{
if (!(value is ClassThatImplementsIPropertyThatIsAnInterface valueAsSpecificType))
{
throw new ArgumentException($"{nameof(value)} is not {typeof(ClassThatImplementsIPropertyThatIsAnInterface)}", nameof(value));
}
InterfaceImplmentationProperty = valueAsSpecificType;
}
}
Run Code Online (Sandbox Code Playgroud)
好吧,我们在上面看到我们必须改变接口的契约才能使其工作。那么...让合同更加灵活怎么样?
我们首先使接口变得通用:
interface IAnInterface<TPropertyThatIsAnInterface>
where TPropertyThatIsAnInterface : IPropertyThatIsAnInterface
{
TPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
在这里遵循您的命名风格。
那么我们在实现的时候就可以指定类型了:
class ClassThatImplementsIAnInterface : IAnInterface<ClassThatImplementsIPropertyThatIsAnInterface>
{
public ClassThatImplementsIPropertyThatIsAnInterface InterfaceProperty { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
如果您确实想要更丑陋的名称,您可以执行显式实现和委托属性操作。
更进一步...该接口的目的是什么?是不是可以通过接口处理对象而不必处理特定类型?- 理想情况下,您不必强制转换或检查类型。
来自评论:
我已实施您的建议,但在尝试填充
List<IFileProcessors<IProcessorParameters>>. 我收到“无法隐式转换类型”错误。
看?您想将它们视为同一类型。然后使它们成为同一类型。
嗯,有一种模式,那就是有两个版本的接口,一个是通用的,另一个不是。那么泛型接口继承自非泛型。我想说的是,如果你能避免这种情况,就避免它。如果有的话,它将导致运行时更多的类型检查。
理想情况下,您应该能够通过其接口处理该类型。接口应该够用了。因此不需要特定类型,因此也不需要强制转换来使用它。
正如我在上面解释的那样,设置器是一个问题。
如果属性的实际类型比接口上的类型更具体,则接口表示该属性允许类不允许的类型。
可以去掉设置器吗?
interface IAnInterface
{
IPropertyThatIsAnInterface InterfaceProperty { get; }
}
interface IPropertyThatIsAnInterface
{
int X { get; set; }
}
class ClassThatImplementsIAnInterface : IAnInterface
{
public IPropertyThatIsAnInterface InterfaceProperty { get; }
}
Run Code Online (Sandbox Code Playgroud)
ClassThatImplementsIAnInterface仍然能够使用InterfaceProperty任何实现IPropertyThatIsAnInterface. 消费者不必意识到这一点。并且,假设IPropertyThatIsAnInterface它确实有用(应该),则无需强制转换即可使用它。这取决于消费者是否可以处理该界面。当消费者需要某种特定类型的时候,你就会进行选角。
| 归档时间: |
|
| 查看次数: |
12784 次 |
| 最近记录: |