首页 文章

如何在派生类中隐藏基类公共属性

提问于
浏览
39

我想在我的派生类中隐藏基本公共属性(数据成员):

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4;// should show an error but it doent ???
    }
}

class a
{
    public int item1 {get; set;}
    public int item2 { get; set; }
}

class b : a
{
    new private int item1;
}

class c : a
{

}

我有成员公开因为我希望成员在c类中继承,但是想要隐藏b类中的成员,我该怎么做?

我没有选择继承我想要在我的基类中的变量???多数民众赞成真的很糟糕,我认为ms应该为我们提供一个选项(可能是修改器)来执行此操作


Edit:

我自己找到了答案(我听到很多人告诉我这在c#中是不可能的,但你可以这样做)

我包含代码以防它有用

class Program
{
    static void Main(string[] args)
    {
        b obj = new b();
        obj.item1 = 4; // shows an error  : )
    }
}

class a
{
    public int item1 { get; set; }
    public int item2 { get; set; }
}

class b : a
{
    new public static int item1
    {
        get;
        private set;
    }
}

16 回答

  • 5

    您可以覆盖它,然后添加[Browsable(false)]标签以防止在设计器中显示它 .

    简单:

    public class a:TextBox
    {
            [Browsable(false)]
            public override string Text
            {
                get { return ""; }
                set { }
            }
    }
    
  • 0

    你不能直接这样做,但你可以覆盖子类中的属性,并使它们只读取,例如

    class Program
    {
        static void Main(string[] args)
        {
            b obj = new b();
            obj.item1 = 4;// should show an error but it doent ???
        }
    }
    
    class a
    {
        public virtual int item1 {get; set;}
        public virtual int item2 { get; set; }
    
    }
    
    class b : a
    {
        public override int item1
        { 
             get { return base.item1; }
             set { }
        }
    }
    
        class c : a
    {
    
    }
    
  • 24

    您可以使用接口来隐藏属性 . 子类将实现一个没有属性的接口,然后它就不会出现 .

    当你想要属性时,你需要两个接口,当你不需要时,你需要两个接口,因此它成为一个可怕的黑客 .

  • 0

    我将尝试用例子解释为什么这是一个坏主意,而不是使用神秘的术语 .

    您的建议是使用如下代码:

    public class Base
    {
        public int Item1 { get; set; }
        public int Item2 { get; set; }
    }
    
    
    public class WithHidden : Base
    {
        hide Item1; // Assuming some new feature "hide" in C#
    }
    
    public class WithoutHidden : Base { }
    

    这将使以下代码无效:

    WithHidden a = new WithHidden();
    a.Item1 = 10; // Invalid - cannot access property Item1
    int i = a.Item1; // Invalid - cannot access property Item1
    

    这就是你想要的 . 但是,假设我们现在有以下代码:

    Base withHidden = new WithHidden();
    Base withoutHidden = new WithoutHidden();
    
    SetItem1(withHidden);
    SetItem1(withoutHidden);
    
    public void SetItem1(Base base)
    {
        base.Item1 = 10;
    }
    

    编译器不知道SetItem1中的参数库将是什么运行时类型,只是它至少是Base类型(或从Base派生的某种类型,但它无法分辨哪个 - 它可能很明显看着代码片段,但更复杂的场景使其几乎不可能) .

    因此,在很大比例的情况下,编译器不会给出编译器错误,即Item1实际上是不可访问的 . 这样就可以进行运行时检查 . 当您尝试在实际上为WithHidden类型的对象上设置Item1时,它将抛出异常 .

    现在访问任何成员,任何非密封类(大多数属性)上的任何属性都可能抛出异常,因为它实际上是隐藏成员的派生类 . 暴露任何非密封类型的任何库在访问任何成员时都必须编写防御性代码,因为有人可能隐藏了它 .

    对此的潜在解决方案是编写该特征,使得只能隐藏声明自己可隐藏的成员 . 然后,编译器将禁止对该类型的变量(编译时)访问隐藏成员,并且还包括运行时检查,以便在将其转换为基类型并尝试从该类型(运行时)进行访问时抛出FieldAccessException . .

    但即使C#开发人员确实为此功能付出了巨大的麻烦和代价(请记住,功能很昂贵,特别是在语言设计方面),仍然必须编写防御性代码以避免潜在的FieldAccessExceptions被抛出的问题,那么有什么优势呢?重组你的继承层次结构你获得了吗?使用新成员隐藏功能,将有大量潜在的地方可以让bug进入您的应用程序和库,从而增加开发和测试时间 .

  • 1

    你想要做的是直接反对OO,你不能“取消发布”成员,因为这违反了替代原则 . 你必须将其重构为其他东西 .

  • 0

    瓦迪姆的回答让我想起了MS在某些地方如何在框架中实现这一目标 . 一般策略是使用EditorBrowsable attribute从Intellisense隐藏成员 . (注意,如果它在另一个程序集中,它只会隐藏它)虽然它不会阻止任何人使用该属性,并且如果它们转换为基本类型它们可以看到它(参见我之前的探索),它使得它更难被发现,因为它没有出现在Intellisense中并保持类的接口干净 .

    尽管如此,只有在重构继承层次结构等其他选项会使其变得复杂得多时,才应谨慎使用它 . 这是最后的手段,而不是第一个想到的解决方案 .

  • 0

    如果使用接口而不是基类来定义属性,则可以显式实现该属性 . 需要对接口进行显式强制转换才能使用该属性 .

    public interface IMyInterface
    {
        string Name { get; set; }
    }
    
    public class MyClass : IMyInterface
    {
    
        string IMyInterface.Name { get; set; }
    
    }
    

    你可以找到更多here .

  • 0

    我唯一能想到的是在class a中使item1成为虚拟:

    class a
    {
        public virtual int item1 { get; set; }
        public int item2 { get; set; }
    
    }
    

    然后在类b中覆盖它,但在getter和setter中抛出异常 . 此外,如果在可视化设计器中使用此属性,则可以使用Browsable attribute来不显示 .

    class b : a
    {
        [Browsable(false)]
        public override int item1
        {
            get
            {
                throw new NotSupportedException();
            }
            set
            {
                throw new NotSupportedException();
            }
        }
    }
    
  • 0

    首先,如果您使用一些操作基类的方法,这不是一个好主意 .
    您可以尝试使用过时的参数使用户两次认为使用此属性 .

    [System.Obsolete("Do not use this property",true)]  
    public override YourType YourProperty { get; set; }
    
  • 0

    你所描述的是类似的东西来自C的'私有继承',在C#中不可用 .

  • 13

    更改虚拟成员的可访问性是C#语言规范明确禁止的继承类:

    覆盖声明和重写的基本方法具有相同的声明可访问性 . 换句话说,覆盖声明不能更改虚拟方法的可访问性 . 但是,如果重写的基本方法在内部受到保护,并且它在与包含override方法的程序集不同的程序集中声明,则必须保护override方法声明的可访问性 .

    从第10.6.4节覆盖方法

    适用于重写方法的相同规则也适用于属性,因此通过继承基类从 publicprivate 无法在C#中完成 .

  • 5

    你真正需要的是接口:

    public interface ProvidesItem1
        {
            int item1 { get; set; }
        }
    
        public interface ProvidesItem2
        {
            int item2 { get; set; }
        }
    
        class a : ProvidesItem1, ProvidesItem2
        {
            public int item1 { get; set; }
            public int item2 { get; set; }
        }
    
        class b : ProvidesItem1
        {
            public int item1 { get; set; }
        }
    

    然后只需传递接口 . 如果类应该使用通用实现,那么将它放在第三个类中,让它们从该类派生,以及实现它们各自的接口 .

  • 0

    对的,这是可能的 . 你对代表团怎么说?我将尝试使用一段代码在OOP中了解所谓的“委托”:

    public class ClassA
    {
        // public
        public virtual int MyProperty { get; set; }
    
        // protected
        protected virtual int MyProperty2 { get; set; }
    }
    
    public class ClassB
    {
        protected ClassC MyClassC;
    
        public ClassB()
        {
            MyClassC = new ClassC();
        }
    
        protected int MyProperty2
        {
            get { return MyClassC.MyProperty2; }
            set { MyClassC.MyProperty2 = value; }
        }
    
        protected int MyProperty
        {
            get { return MyClassC.MyProperty; }
            set { MyClassC.MyProperty = value; }
        }
    
        protected class ClassC : ClassA
        {
            public new int MyProperty2
            {
                get { return base.MyProperty2; }
                set { base.MyProperty2 = value; }
            }
    
            public override int MyProperty
            {
                get { return base.MyProperty; }
                set { base.MyProperty = value; }
            }
        }
    }
    
  • 0
    namespace PropertyTest    
    {    
        class a
        {    
            int nVal;
    
            public virtual int PropVal
            {
                get
                {
                    return nVal;
                }
                set
                {
                    nVal = value;
                }
            }
        }
    
        class b : a
        {
            public new int PropVal
            {
                get
                {
                    return base.PropVal;
                }
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                a objA = new a();
                objA.PropVal = 1;
    
                Console.WriteLine(objA.PropVal);
    
                b objB = new b();
                objB.PropVal = 10; // ERROR! Can't set PropVal using B class obj. 
                Console.Read();
            }
        }
    }
    
  • 4
    class CreditCard
    {
        public string CardName { get; set; }
        public string CardNumber(string value) => "XXX57879";
    }
    class GoldCard : CreditCard
    {
        public new string CardName { get; set; }//method hiding 
        public new int CardNumber(string value) => 1234567;
    }
    

    you can hide base class method using new keyword

  • 0

    如果你想隐藏基类中的成员,那么你需要添加一个新的基类让我们称之为baseA,你的代码应如下所示:

    class Program
    {
        static void Main(string[] args)
        {
            b obj = new b();
            obj.item1 = 4;// should show an error but it doent ???
        }
    }
    
    class baseA
    {
        public int item2 { get; set; }
    }
    class a:baseA
    {
        public int item1 { get; set; }        
    }
    
    class b : baseA { }
    
    class c : a { }
    

相关问题