简体   繁体   English

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

[英]How can I hide a base class public property in the derived class

I want to hide the base public property(a data member) in my derived class:我想在我的派生类中隐藏基本公共属性(数据成员):

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
{

}

i have member as public because i want the member to be inherited in c class , but want to hide the member in b class , how can i do this ?我有一个 public 成员,因为我希望成员在 c 类中被继承,但想隐藏 b 类中的成员,我该怎么做?

dont i have an option to selectively inherite the variable i want in my base class ???我没有选择在我的基类中选择性地继承我想要的变量吗??? thats really bad , i think ms should provide us with an option (may be a modifier) to perform this那真的很糟糕,我认为 ms 应该为我们提供一个选项(可能是一个修饰符)来执行此操作


Edit:编辑:

I found the answer myself (i heard lots of them telling this is not possible in c#, but you can kind of do it)我自己找到了答案(我听到很多人说这在 c# 中是不可能的,但你可以这样做)

I am including the code in case it is useful我包括代码以防它有用

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

I'm going to attempt to explain with examples why this is a bad idea, rather than using cryptic terms.我将尝试用例子来解释为什么这是一个坏主意,而不是使用神秘的术语。

Your proposal would be to have code that looks like this:您的建议是使用如下所示的代码:

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

This would then make the following code invalid:这将使以下代码无效:

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

And that would be just what you wanted.而这正是你想要的。 However, suppose we now have the following code:但是,假设我们现在有以下代码:

Base withHidden = new WithHidden();
Base withoutHidden = new WithoutHidden();

SetItem1(withHidden);
SetItem1(withoutHidden);

public void SetItem1(Base base)
{
    base.Item1 = 10;
}

The compiler doesn't know what runtime type the argument base in SetItem1 will be, only that it is at least of type Base (or some type derived from Base, but it can't tell which -- it may be obvious looking at the code snippet, but more complex scenarios make it practically impossible).编译器不知道 SetItem1 中的参数 base 将是什么运行时类型,只知道它至少是 Base 类型(或从 Base 派生的某种类型,但它无法分辨是哪种类型——查看代码片段,但更复杂的场景使其几乎不可能)。

So the compiler will not, in a large percentage of the cases, be able to give a compiler error that Item1 is in fact inaccessible.因此,在大部分情况下,编译器将无法给出 Item1 实际上无法访问的编译器错误。 So that leaves the possibility of a runtime check.所以这就留下了运行时检查的可能性。 When you try and set Item1 on an object which is in fact of type WithHidden it would throw an exception.当您尝试在实际上是 WithHidden 类型的对象上设置 Item1 时,它会引发异常。

Now accessing any member, any property on any non-sealed class (which is most of them) may throw an exception because it was actually a derived class which hid the member.现在访问任何成员,任何非密封类(大多数)上的任何属性都可能引发异常,因为它实际上是隐藏该成员的派生类。 Any library which exposes any non-sealed types would have to write defensive code when accessing any member just because someone may have hidden it.任何暴露任何非密封类型的库在访问任何成员时都必须编写防御性代码,因为有人可能隐藏了它。

A potential solution to this is to write the feature such that only members which declare themselves hideable can be hidden.一个潜在的解决方案是编写该功能,以便只有声明自己可隐藏的成员才能隐藏。 The compiler would then disallow any access to the hidden member on variables of that type (compile time), and also include runtime checks so that a FieldAccessException is thrown if it is cast to the base type and tried to be accessed from that (runtime).然后,编译器将禁止对该类型变量的任何隐藏成员的访问(编译时),并且还包括运行时检查,以便在将 FieldAccessException 强制转换为基类型并尝试从中访问(运行时)时抛出 FieldAccessException .

But even if the C# developers did go to the huge trouble and expense of this feature (remember, features are expensive , especially in language design) defensive code still has to be written to avoid the problems of potential FieldAccessExceptions being thrown, so what advantage over reorganising your inheritance hierarchy have you gained?但是即使 C# 开发人员确实为此功能付出了巨大的麻烦和代价(记住,功能是昂贵的,尤其是在语言设计中)仍然需要编写防御性代码来避免抛出潜在的 FieldAccessExceptions 的问题,那么有什么优势呢?重组您的继承层次结构您获得了吗? With the new member hiding feature there would be a huge number of potential places for bugs to creep into your application and libraries, increasing development and testing time.使用新的成员隐藏功能,将有大量潜在的错误可以潜入您的应用程序和库,从而增加开发和测试时间。

What you want to do goes directly against the grain of OO, you can't 'unpublish' members as this violates the substitution principle.您想要做的事情直接违背了 OO 的原则,您不能“取消发布”成员,因为这违反了替换原则。 You have to refactor this into something else.您必须将其重构为其他内容。

Vadim's response reminded me of how MS achieve this in the Framework in certain places. Vadim 的回应让我想起了 MS 如何在某些地方的框架中实现这一点。 The general strategy is to hide the member from Intellisense using the EditorBrowsable attribute .一般策略是使用EditorBrowsable 属性对Intellisense 隐藏成员。 (NB This only hides it if it is in another assembly) Whilst it does not stop anyone from using the attribute, and they can see it if they cast to the base type (see my previous explination) it makes it far less discoverable as it doesn't appear in Intellisense and keeps the interface of the class clean. (注意,如果它在另一个程序集中,这只会隐藏它)虽然它不会阻止任何人使用该属性,并且如果他们转换为基本类型,他们可以看到它(请参阅我之前的解释)它使它更不容易被发现不会出现在 Intellisense 中并保持类的界面干净。

It should be used sparingly though, only when other options like restructuring the inheritance hierarchy would make it a lot more complex.它应该谨慎,虽然可以使用,只有当像重组继承层次其他的选择会使它复杂得多 It's a last resort rather than the first solution to think of.这是最后的手段,而不是第一个想到的解决方案。

If you use an interface instead of a base class for defining the property, you could implement the property explicitly.如果您使用接口而不是基类来定义属性,则可以显式实现该属性。 The would require an explicit cast to the interface to use the property.需要对接口进行显式转换才能使用该属性。

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

public class MyClass : IMyInterface
{

    string IMyInterface.Name { get; set; }

}

You can find more out here .您可以 在此处找到更多 信息

The only thing I can think of is to make item1 virtual in class a:我唯一能想到的就是在 a 类中将 item1 设为虚拟:

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

}

and then override it in class b but throw an exception in getter and setter.然后在 b 类中覆盖它,但在 getter 和 setter 中抛出异常。 Also if this property is used in a visual designer you can use Browsable attribute to not display.此外,如果在可视化设计器中使用此属性,您可以使用Browsable 属性不显示。

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

First of all this is not good idea if you using some methods, that operates base class.首先,如果您使用某些操作基类的方法,这不是一个好主意。
You can try to use obsolete argument to make users twice think to use this property.您可以尝试使用过时的参数让用户三思而后行。

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

You can override it and then Add a [Browsable(false)] tag to prevent showing it in designer.您可以覆盖它,然后添加 [Browsable(false)] 标签以防止在设计器中显示它。

Simple:简单的:

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

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

You cant do it directly, but you could override the properties in the child class and make them readonly eg您不能直接执行此操作,但您可以覆盖子类中的属性并使它们只读,例如

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
{

}

You could use interfaces to hide the property.您可以使用接口来隐藏该属性。 The child class would implemented an interface that didn't have the property then it wouldn't appear.子类将实现一个没有属性的接口,然后它就不会出现。

You would need two interfaces for when you want the property and when you don't, thus making it a horrible hack.您需要两个接口,分别用于何时需要该属性和何时不需要该属性,从而使其成为一个可怕的黑客。

Changing the accessibility of a virtual member is an inheriting class is specifically prohibited by the C# language spec:更改虚拟成员的可访问性是 C# 语言规范明确禁止的继承类:

The override declaration and the overridden base method have the same declared accessibility.覆盖声明和覆盖的基方法具有相同的声明可访问性。 In other words, an override declaration cannot change the accessibility of the virtual method.换句话说,覆盖声明不能改变虚方法的可访问性。 However, if the overridden base method is protected internal and it is declared in a different assembly than the assembly containing the override method then the override method's declared accessibility must be protected.但是,如果重写的基方法是受保护的内部方法,并且它是在与包含重写方法的程序集不同的程序集中声明的,则必须保护重写方法声明的可访问性。

From section 10.6.4 Override methods来自 10.6.4 节覆盖方法

The same rules which apply to overriding method also apply to properties, so going from public to private by inheriting from the base class can't be done in C#.适用于覆盖方法的相同规则也适用于属性,因此无法在 C# 中通过从基类继承来实现从publicprivate

If you wanna hide a member from base class then you will need to add a new base class let's call it baseA and your code should be as follows:如果你想从基类中隐藏一个成员,那么你需要添加一个新的基类,我们称之为 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 { }

What you actually need are interfaces:你真正需要的是接口:

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

Then just pass the interfaces around.然后只需传递接口。 If the classes should use a common implementation, put that in a third class and let them derive from that class aswell as implement their respective interface.如果类应该使用公共实现,请将其放在第三个类中,让它们从该类派生并实现各自的接口。

Yes, it is possible.对的,这是可能的。 What say you on the delegation.你对代表团怎么说。 I will try to give an idea of what is called "delegation" in OOP with a piece of code:我将尝试通过一段代码来了解 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; }
        }
    }
}
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();
        }
    }
}

You can user new modifer.您可以使用new修改器。

Sample;样本;

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.*/ 
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 隐藏派生类中基类的公共属性 - Hide Public Properties of Base Class in Derived Class C#:如何从派生类设置属性的最大值? (而不是在基类中) - C#: How can I set a maximal Value of a property from a derived class? (And not in base class) 如何在不使用方法或构造函数的情况下直接访问派生 class 中的基本 class 属性? - How can I directly access my base class property in the derived class without using methods or constructors? 如何在派生1和派生2中而不是基类中访问结果 - How can I access the result in Derived 1 and Derived 2 and not the base class 如何实例化基类,然后将其转换为派生类? - How can I instantiate a base class and then convert it to a derived class? 我怎样才能转换Class <Derived> 上课 <Base> ? - How can I convert Class<Derived> to Class<Base>? 如何使用NHibernate在基类上映射派生属性? - How do I map a derived property on a base class using NHibernate? 我怎样才能钩住基类派生类的所有属性设置器? - How can I hook into all property setters of derived classes from a base class? 如何在基类上使用派生属性? - How to use a derived property on a base class? 如何在派生类中调用,访问基类的公共成员 - How to invoke, access public members of base class in derived class
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM