简体   繁体   中英

C# Inheritance to hide inherited Members

I read other threads like this but they didn't work for me.

I got two classes:

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.


}

If I now create a new object of ClassB I get

 _shouldBeInteger, _shouldBeBool, _shouldBeDateTime;
 shouldBeInteger,shouldBeBool,shouldBeDateTime

But I want to hide the _variables to the User. Setting them private in ClassB will override them, but I need to access them in order to parse there string values.

Update

There is a ClassC filling ClassAs' values, which mainly is the reason why they have to be writeable. There is no way for me to change the way that works, but I'm fully in Control of ClassA and ClassB

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

Setting ClassA variables to private won't work, because programmer of ClassA produced it in a strange way.

Solution

Because ClassA needs to be writeable, but not readable to other classes than inheritated, I finally got this:

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

which causes ClassB to work with theese properties, without giving them outside. Intellisense still shows them, but you might consider using:

 [EditorBrowsable(EditorBrowsableState.Never)]

to solve that.

Thanks to all.

I think you can solve your problem using:

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

so those variables are accessible to derived classes but not to user.

EDITED after user update:
I don't know if this could be a vali solution for you, but try:

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

Inheritance can't hide the members as you would think. The new modifier exists to "hide" a base member, but that doesn't play nice when talking to base types.

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

You can either change the access level of the fields (the preferred way) or you can wrap the class instead of inheriting from it and provide simple pass-through methods to delegate to the wrapped class. This is called the Adapter Pattern :

public class ClassB
{
    private ClassA _wrappedClass;
}

Just as an aside, your public fields are following the naming convention commonly used for private fields.

The required access level for derived classes is protected . If the members are used publicly but in the same assembly you can use protected internal . If the members are used publicly by other assemblies... I'd suggest refactoring.

The problem is that you declared the fields public in the base class. In order not to violate the polymorphic nature of inheritance, anything public in the base class must be public in all derived classes as well. If you could change that, you could never be sure that a ClassB could be passed to something expecting a ClassA.

Therefore, as other people have suggested, you probably want the base class fields to be declared protected, which is like private except derived classes can see them.

However if you do need to access them via an actual instance of ClassA, you could declare them private and give them virtual public properties which the derived class can then override. This at least allows the derived class to change their behaviour, but it still can't actually hide them.

If that also doesn't fit, then it's probably worth considering using composition instead of inheritance because the substitution principle is actually getting in your way, and that's an inheritance fundamental.

If you don't have control over ClassA, you'll need to create a wrapper/adapter class like so:

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);
        }
    } 
}
public class ClassB
{
    private int shouldBeInteger;

    public int ShouldBeInteger
    {
        get { return shouldBeInteger; }
        set { shouldBeInteger = value; }
    }

}

OR

  public class ClassB
  {

    public int ShouldBeInteger{ get; set; }

  }

In both of this case ShouldBeInteger will be accesible outside the class.

In first case there were a private field, which cannot be accesible outside the class,

values to private filed can be set through the public field.

In second case the compiler automatically create a private backing field and do the same

process as above. This is auto implemented property.

Hope this may help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM