【问题标题】:How to redefine a property in C# through interface inheritance?如何通过接口继承重新定义C#中的属性?
【发布时间】:2015-01-26 17:12:34
【问题描述】:

我有一个接口“IBase”,它指定了一个可为空的 int。稍后的接口“IDerived”隐藏了可为空的 int 并将其“重新定义”为不可为空。

interface IBase
{
    int? Redefineable { get; set; }
}

interface IDerived : IBase
{
    new int Redefineable { get; set; }
}

实现这些接口的类必须显式实现 hidden 属性,但它是私有的,因此客户端看不到它。

class TheClass : IDerived
{
    public int Redefineable { get; set; }
    int? IBase.Redefineable { get; set; }
}

但是,即使它是私有属性,我仍然可以通过 IBase 接口访问它!

var o = new TheClass();
o.Redefineable = 1; // ok

var hack = o as IBase;
hack.Redefineable = null; // uh!

这似乎违反了 C# 访问修饰符,但无论哪种方式,这都不是我重新定义(不仅仅是隐藏)属性的真正想法。从某种意义上说,它按照您的要求进行操作,获得一个可以为空的 int 的 IBase 接口,但这对于可以修改 wrong 版本属性的客户端来说是不直观的。

我真正想要的是,如果客户端访问 IBase.Redefinable,那么它的行为就好像它正在访问 IDerived.Redefinable 属性,即 TheClass 的“真实”属性。这样它实际上就被重新定义了,就像在层次结构中一样。

class TheClass : IDerived
{
    public int Redefineable { get; set; }
    int? IBase.Redefineable { 
        get { 
            // redirect to redefined property
            return this.Redefineable; 
        }
        set
        {
            // stop client setting it to null
            if (!value.HasValue)
                throw new InvalidOperationException();

            // redirect to redefined property
            this.Redefineable = value.Value;
        }
    }
}

这感觉就像一个 hack,几乎好像我错过了什么,所以我想问是否有人知道实现可重新定义属性的更好/替代方法?

【问题讨论】:

  • 我认为您需要重新了解多态性的工作原理。如果你有一个IBase 并且你正在使用它的属性,那将是IBase 定义它的方式。如果您有一个 IDerived 并且您正在使用它的属性,那么它将是 IDerived 定义它的方式。
  • 这就是它的工作原理。
  • 显式接口实现不是通常意义上的private。因此,不允许为它们指定 private 修饰符。
  • 使用new 修饰符隐藏一个成员(这里是一个属性)是不是“重新定义”它。它只是介绍另一个看起来相同的成员。这很少是一件好事。原始成员不会被删除,并且始终可以通过向上转换为定义它的类型(这里是基接口)来使用它。
  • 显式接口实现只是为了解决歧义问题,因为必须实现两个同名成员。这不是访问限制。

标签: c# properties interface redefine explicit-interface


【解决方案1】:

但是,即使它是私有属性,我仍然可以通过 IBase 接口访问它!

这不是私有财产。它只是一个使用显式接口实现的属性。这意味着它通过界面公开,但可通过界面使用。显式接口实现主要是为了使实现“矛盾”接口变得可行,以及用于“劝阻”(但不禁止)使用某些接口方法。 是为了给人一种成员根本不存在的印象。

从根本上说,您不应该在这里使用继承 - 如果您不希望某些东西能够充当 IBase,则不应从 IBase 继承。

【讨论】:

  • 好的,感谢您提供有关私人/公共问题的信息。我确实希望它充当 IBase - 在所有其他情况下,除了访问该属性外,显然这是问题的简化示例,在实际代码中,层次结构中有大约 30 个接口实现多重继承,相当于IBase 位于中间的某个位置,它也有其他属性。我会说它 is 是一个 IBase - 但具有 redefined 属性。我不知道实现它的更好方法,因此我的问题。
  • @MarkB:但是一个类似于 IBase 但具有不同属性类型的接口根本不是 IBase。也许您应该在自己的接口中拥有该属性,因此您可以有两个替代接口,具体取决于它是否应该具有类型 int?int...
  • 当然,但我实际上所做的只是为该接口的实现添加一个规则,因此虽然它被定义为可为空,但尝试将值设置为 null(在某些实现类上)将导致异常。如果将 int 设置为数字 5,它与抛出异常的 int 有什么不同吗?
  • @MarkB:是的 - 您正在尝试更改它的类型。如果您只想以特定方式实现它,那很好(只要记录了接口,实现可能会对值提出特定要求)。如果您对此感到满意 - 如果没有 IBase 客户端将期望设置 null 值 - 那么您所获得的实现似乎是合理的。
  • Microsoft 有一个相同系统的实现,它们只是在层次结构中不包含可为空的“版本”。这违反了规范(UML 2.x),我不确定它是否违反了合规性。我查看了您的两个替代接口想法,但它使层次结构以及支持的客户端代码过于复杂,并且接口与规范不一致,但这是我将来会考虑的一个。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-07
  • 1970-01-01
  • 2021-06-19
  • 2016-10-06
  • 1970-01-01
相关资源
最近更新 更多