【问题标题】:C# Inheritance to hide inherited MembersC#继承隐藏继承的成员
【发布时间】:2012-02-13 23:17:13
【问题描述】:

我阅读了其他主题,例如 this,但它们对我不起作用。

我有两门课:

public class ClassA 
{
    public string _shouldBeInteger;
    public string _shouldBeBool;
    public string _shouldBeDateTime;
}

public class ClassB : ClassA
{
   public int? shouldBeInteger
    {
        get { return (_shouldBeInteger != null) ? Convert.ToInt32(Convert.ToDouble(_shouldBeInteger)) : new int?(); }
        set { _shouldBeInteger = Convert.ToString(value); }
    } 

  //... same thing with datetime etc.


}

如果我现在创建一个 ClassB 的新对象,我会得到 ​​p>

 _shouldBeInteger, _shouldBeBool, _shouldBeDateTime;
 shouldBeInteger,shouldBeBool,shouldBeDateTime

但我想向用户隐藏 _variables。 在 ClassB 中将它们设置为私有将覆盖它们,但我需要访问它们才能解析字符串值。

更新

有一个 ClassC 填充 ClassAs 的值,这主要是它们必须是可写的原因。我无法改变工作方式,但我完全控制了 ClassA 和 ClassB

ClassC //not changeAble for me
{
 //infomagic filling values of ClassA    
}

将 ClassA 变量设置为 private 将不起作用,因为 ClassA 的程序员以一种奇怪的方式生成它。

解决方案

因为 ClassA 需要可写,但不能被继承的其他类读取,我终于得到了这个:

ClassA 
{ 
  public string _shouldBeInteger { protected get; set; } 
  //and so on
} 

这会导致 ClassB 使用这些属性,而不会将它们提供给外部。 Intellisense 仍会显示它们,但您可以考虑使用:

 [EditorBrowsable(EditorBrowsableState.Never)]

解决这个问题。

谢谢大家。

【问题讨论】:

  • 当您说将字段设置为私有不起作用时,它们需要公开还是受保护的工作?
  • 下划线前缀是private members的标准,而不是public members
  • 只是对@gdoron 的评论进行挑剔,下划线前缀不符合 CLS,因此不符合标准,但私有成员不是 CLS 合规性的问题。因此,它们被允许并具有以下优势:如果您在探索问题时将某些私有内容移至公共,CLS 合规性警告将标记它不处于最终发布的良好状态。
  • “因为 ClassA 的程序员以一种奇怪的方式制作了它”——该死的,他做到了!
  • @JonHanna 这是一个很好的观点。 .NET 语言不保证/不要求支持带有前导下划线的成员名称。虽然我不知道有任何 .NET 语言不知道。

标签: c# .net oop class object


【解决方案1】:

我认为您可以使用以下方法解决您的问题:

public class ClassA 
{
    protected string _shouldBeInteger;
    protected string _shouldBeBool;
    protected string _shouldBeDateTime;
}

所以派生类可以访问这些变量,但用户不能访问这些变量。

用户更新后编辑:
我不知道这是否适合您,但请尝试:

public class ClassB : ClassA
{
    public new int? _shouldBeInteger
    {
        get { return (base._shouldBeInteger != null) ?
                     Convert.ToInt32(Convert.ToDouble(base._shouldBeInteger)) : 
                     new int?(); }
        set { base._shouldBeInteger = Convert.ToString(value); }
    }
}

【讨论】:

  • 有人能解释为什么投反对票吗?我的回答有什么问题?
  • +1 不确定,除了可能的字段名称之外,使它们受到保护是一个有效的解决方案。除非他们被要求公开,但 OP 没有这么说。
  • sry 否决了投票,因为我从他无法控制 ClassA 的问题中得到印象。如果不是这样,我会取消投票:)
  • @MattDavey:他什么也没说……或者我很确定 OP 没有告诉我们。无论如何,好的,如果有理由,我会接受反对票! :)
  • 我对问题最后一句话的解释是,由于未指明的原因,OP 不想或无法更改 ClassA - 我想有很多方法可以解释这句话。 Downvote 并不是说​​你的答案是错误的,只是在我对 OPs 场景的解释中它不可行.. :)
【解决方案2】:

继承不能像你想的那样隐藏成员。 new 修饰符的存在是为了“隐藏”一个基成员,但在与基类型对话时效果不佳。

http://msdn.microsoft.com/en-us/library/435f1dw2.aspx

您可以更改字段的访问级别(首选方式),或者您可以包装类而不是从它继承,并提供简单的传递方法来委托给被包装的类。这被称为Adapter Pattern

public class ClassB
{
    private ClassA _wrappedClass;
}

顺便说一句,您的公共字段遵循私有字段常用的命名约定。

派生类所需的访问级别是protected。如果成员被公开使用但在同一个程序集中,您可以使用protected internal。如果成员被其他程序集公开使用...我建议重构。

【讨论】:

  • 观看 OP 更新我编辑了我的答案:你怎么看?会不会是一条出路?
  • 包装类.. 当然可能。现在找到了另一种方法,但下次我会早点考虑。谢谢。
【解决方案3】:

问题是您在基类中声明了公共字段。为了不违反继承的多态性,基类中的任何公共内容在所有派生类中也必须是公共的。如果你可以改变它,你永远无法确定 ClassB 可以传递给期望 ClassA 的东西。

因此,正如其他人所建议的,您可能希望将基类字段声明为受保护的,这就像私有的,但派生类可以看到它们。

但是,如果您确实需要通过 ClassA 的实际实例来访问它们,您可以将它们声明为私有并赋予它们虚拟的公共属性,然后派生类可以覆盖这些属性。这至少允许派生类改变它们的行为,但它仍然不能真正隐藏它们。

如果这也不合适,那么可能值得考虑使用组合而不是继承,因为替换原则实际上妨碍了你,这是继承的基础。

【讨论】:

    【解决方案4】:

    如果您无法控制 ClassA,则需要创建一个包装器/适配器类,如下所示:

    public class ClassB
    {
        private readonly _classA = new ClassA();
    
        public int? shouldBeInteger
        {
            get
            {
                return (this._classA._shouldBeInteger != null)
                    ? Convert.ToInt32(Convert.ToDouble(this._classA._shouldBeInteger))
                    : new int?();
           }
            set
            {
                this._classA._shouldBeInteger = Convert.ToString(value);
            }
        } 
    }
    

    【讨论】:

    • 不要使用 ClassA 作为内部类名...最好是 private classA = new ClassA(); :)
    • @Marco 你说得对,本来它是私有财产,但我在最后一分钟把它改成了一个字段 :)
    【解决方案5】:
    public class ClassB
    {
        private int shouldBeInteger;
    
        public int ShouldBeInteger
        {
            get { return shouldBeInteger; }
            set { shouldBeInteger = value; }
        }
    
    }
    

      public class ClassB
      {
    
        public int ShouldBeInteger{ get; set; }
    
      }
    

    在这两种情况下,ShouldBeInteger 都可以在类外访问。

    在第一种情况下,有一个私有字段,不能在类外访问,

    可以通过公共字段设置私有字段的值。

    在第二种情况下,编译器会自动创建一个私有支持字段并执行相同的操作

    如上处理。这是自动实现的属性。

    希望对你有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-05
      • 2011-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多