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

时间:2009-09-18 11:12:01

标签: c#

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

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应该为我们提供一个选项(可能是一个修改器)来执行这个


修改

我自己找到了答案(我听说很多人说这在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 个答案:

答案 0 :(得分:24)

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

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

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 :(得分:12)

你想做的事情直接针对OO,你不能'取消发布'成员,因为这违反了替代原则。你必须将其重构为其他东西。

答案 2 :(得分:6)

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

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

答案 3 :(得分:5)

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

public interface IMyInterface
{
    string Name { get; set; }
}

public class MyClass : IMyInterface
{

    string IMyInterface.Name { get; set; }

}

您可以找到更多here

答案 4 :(得分:4)

我唯一能想到的就是在第一课中使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();
        }
    }
}

答案 5 :(得分:1)

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

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

答案 6 :(得分:0)

您所描述的内容类似于C ++中的“私有继承”,并且在C#中不可用。

答案 7 :(得分: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
{

}

答案 8 :(得分:0)

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

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

答案 9 :(得分: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();
        }
    }
}

答案 10 :(得分:0)

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

简单:

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

答案 11 :(得分:0)

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

  

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

从第10.6.4节“覆盖方法”

适用于覆盖方法的相同规则也适用于属性,因此通过继承基类从public转到private无法在C#中完成。

答案 12 :(得分: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 { }

答案 13 :(得分:0)

您实际需要的是接口:

    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; }
    }

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

答案 14 :(得分: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; }
        }
    }
}

答案 15 :(得分:0)

您可以使用 new 修饰符。

样品;

public class Duck
{
    public string Color{get; set;}
    public void Swim() { }
}
public class DonaldDuck : Duck
{
    new public void Swim() 
    { 
        /*you could call in DonaldDuck.Swim  only here but not public for DonaldDuck client.*/ 
    }
}