简体   繁体   中英

hiding non-generic base class property in a generic class

What is the standard pattern for hiding non-generic base class property or method in generic class?

I Have 2 solution what is actually do the same but different approach. Solution one use more memory because the base and derived class reference the same object and Solution two is slower because the casting.(or maybe i wrong?)

Base classes:

public class MyDataBase {}

public class MyDataDerived : MyDataBase {}

 public class BaseFoo
 {
     private readonly MyDataBase _data;
     public MyDataBase Data { get { return _data; } }

     public BaseFoo(MyDataBase data) {
      _data = data;
  }
}

Solution 1:

public class GenericFooWithHiding<T> : BaseFoo where T : MyDataBase
{
     private readonly T _data;

     public GenericFooWithHiding(T data) : base(data) { _data = data; }

     public new T Data { get { return _data; } }
 }

Solution 2:

public class GenericFooWithCasting<T> : BaseFoo where T : MyDataBase
{
     public GenericFooWithCasting(T data) : base(data) {}

     public new T Data { get { return base.Data as T; } }
}

I would go second (cast) approach if I were to chose from these two: having the same data stored in more than one place is pretty much guaranteed way to get them out of sync. So I'd play casting cost (unlikely to be significant), if performance is important - measure and verify.

Side note: I would try avoid new properties as it will cause confusion what is called depending on what variable type you have. Making base class' Data property protected may be potential solution in particular sample.

Solution 3

Reverse the relationship of inheritance between BaseFoo and GenericFoo<T> , thus the use of generic becomes significant and doesn't need to hide at all.

public class MyDataBase {
}

public class MyDataDerived: MyDataBase {
}

public class GenericFoo<T> where T: MyDataBase {
    public GenericFoo(T data=default(T)) {
    }

    public T Data {
        get {
            return _data;
        }
    }

    protected readonly T _data;
}

public class DerivedFoo: GenericFoo<MyDataDerived> {
    public DerivedFoo(MyDataDerived data=default(MyDataDerived))
        : base(data) {
    }
}

public class BaseFoo: GenericFoo<MyDataBase> {
    public BaseFoo(MyDataBase data=default(MyDataBase))
        : base(data) {
    }
}

I assume that you cannot change the type BaseFoo since otherwise you could make it generic in the first place.

I would not use new to change the return type since this might get confusing. For example: what is the type of data in this code snippet?

GenericFoo<MyDataDerived> foo = new GenericFoo<MyDataDerived>(new MyDataDerived());
var data = ((BaseFoo)foo).Data;

It is MyDataBase (the call goes to BaseFoo ). If however you have a virtual property in BaseFoo which is overridden in GenericFoo , which will be called?:

public class BaseFoo
{
    public virtual MyDataBase MoreData
    {
        get
        {
            return _data;
        }
    }
}

public class GenericFoo<T> : BaseFoo where T : MyDataBase
{
    public override MyDataBase MoreData
    {
        get
        {
            return _someOtherData;
        }
    }
}

// which property is called?
var data = ((BaseFoo)foo).MoreData;

This time the call goes to GenericFoo . Since this is usually the expected behaviour I would suggest not to use new .

I would implement a method in GenericFoo to avoid the use of new (and I would use a cast):

public class GenericFoo<T> : BaseFoo
    where T : MyDataBase
{
    public T GetData()
    {
        return (T)base.Data;
    }
}

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