Extend, wrap, or both to add generics to a class that should have had them?

So I’m using a C# framework that has a great example of where generics would be useful, except they weren’t used. For simplicity’s sake, we will say it was a list (I know C# has its own list), but instead of being List where I can specify the T, they made it List, resulting in nightmarish type checking throughout the code.

I want to fix this, but I can’t edit the framework.

So I see three ways to fix this.

Extend, wrap, or both.

So the basic question is, which is the best way to add generics?

Is there a design pattern particulary for this?

Now, while I’m not sure wrapping or extending is better, if this was a simple case I would have gone with one of them and not even considered doing both.

But, the CustomList is used everywhere, and I only want to replace it bit by bit.

Extending allows me to use the TypedCustomList as a CustomList, so that if I change where CustomList are being created to instead by TypedCustomList, later in code’s execution the code can still treat it like a CustomList.

But, I can’t treat a CustomList object as a TypedCustomList (even if I ensure the generic type is correct for that given CustomList). (Or am I missing how to do this, which would solve the problem?)

If a wrap it, I can now work with existing CustomLists, but I have to expose the internal CustomList object to pass it on to other code (for example, if I call a method expecting CustomList, I have to do instanceOfTypedCustomList._customList, I cannot pass instanceOfTypedCustomList).

If I wrap and extend it, I get take an existing CustomList and treat it like a TypedCustomList while still being able to treat my TypedCustomList as a CustomList. But, as you can see below, the ‘Both’ option looks the worst.

Extending

public class TypedCustomList<T> : CustomList
{
  public TypedCustomList()
    :base()
  {
  }

  public T getElementAt(int i)
  {
    return (T) base.getElementAt(i);
  }

  public void addElement(T element)
  {
    base.addElement(element);
  }

  ...ect.
}

Wrapping:

public class TypedCustomList<T>
{
  CustomList _customList { get; private set;}
  public TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    return (T) _customList.getElementAt(i);
  }

  public void addElement(T element)
  {
    _customList.addElement(element);
  }

  ...ect.
}

Both:

public class TypedCustomList<T> : CustomList
{
  private CustomList _customList;

  public TypedCustomList()
    :base()
  {
    _customList = null;
  }

  public TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    if(_customList == null)
    {
      return (T) base.getElementAt(i);
    }
    else
    {
      return (T) _customList.getElementAt(i);
    }
  }

  public void addElement(T element)
  {
    if(_customList == null)
    {
      base.addElement(element);
    }
    else
    {
      _customList.addElement(element);
    }
  }

  ...ect.
}

P.S.

More background which may be relevant to the problem.

There is one class that has a CustomList that is used all over the application, with different parts of the application with each instance having different object types (over a dozen in total). I want to eventually have this class have a unique TypedCustomList for every use. But until I can be sure that all references to it’s CustomList are gone, I wanted to add some error handling. So I was adding something like the following:

public ClassThatUsesCustomList
{
...
private CusotmList _list;
private TypedCustomList<SomeObject> _SomeObjectCustomList;

public CustomList list
{
    get
    {
      //Already existing code
      if(_list == null)
      {
        _list = new CustomList();
      }

      //My code
      catchMissedGetSet(_list);


      return _list;
    }
    set
    {
      catchMissedGetSet(value);
      _list = value;
    }
}

public SomeObjectCustomList
{
  get
  {
    if(_SomeObjectCustomList == null)
    {
      _SomeObjectCustomList = new TypedCustomList<SomeObject>();
    }

    return _SomeObjectCustomList;
  }
  set
  {
    _SomeObjectCustomList = value;
  }
}


private void catchMissedGetSet(CustomList cl)
{
  bool findMissedSpots = true;

  if(cl == null || cl.Count == 0 || cl[0] is SomeObject)
  {
    SomeObjectCustomList = new SomeObjectCustomList(cl);  //Using wrapping.
    if(findMissedSpots && System.Diagnostics.Debugger.IsAttached)
    {
      System.Diagnostics.Debugger.Break();  
      //Hey, you missed a place.  Use step out to find it.
    }
  }
}


...
}

I did this to catch any spots I missed and to avoid any bugs. It requires me wrapping it (as far as I can tell).

12

The answer is wrapping, but it is considerably more work than implied here. I see why you are trying to do this though, because after a certain size of the code base it indeed can be a nightmare to work with typecasting every time you call a library function. Subclassing CustomList is not advisable, as it would expose all the functions that return or expect an object. Having a public property as in the second example is, for the same reason, also unadvisable. I believe you are facing a situation similar to the following:

interface Producer
{
  CustomList produce();
}

interface Consumer
{
  void consume(CustomList list);
}

This is how I would wrap it:

public class TypedCustomList<T>
{
  private readonly CustomList _customList;
  internal CustomList customList
  {
    get { return _customList; }
  }

  internal TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    return (T) _customList.getElementAt(i);
  }

  public void addElement(T element)
  {
    _customList.addElement(element);
  }

  ... ect.
}

The producer:

class TypedProducer<T>
{
  private readonly Producer producer = new Producer();
  public TypedCustomList<T> produce()
  {
    return new TypedCustomList<T>(producer.produce())
  }
}

The consumer:

class TypedConsumer<T>
{
  private readonly Consumer consumer = new Consumer();
  public void consume(TypedCustomList<T> list)
  {
    consumer.consume(list.customList);
  }
}

You will need to put the wrapping classes to their own assembly, so that they hide the internal parts.

I can safely suggest you this solution, which I beleive generally considered a good practice. You will need to wrap the subset of the library you are using in this manner.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa

Extend, wrap, or both to add generics to a class that should have had them?

So I’m using a C# framework that has a great example of where generics would be useful, except they weren’t used. For simplicity’s sake, we will say it was a list (I know C# has its own list), but instead of being List where I can specify the T, they made it List, resulting in nightmarish type checking throughout the code.

I want to fix this, but I can’t edit the framework.

So I see three ways to fix this.

Extend, wrap, or both.

So the basic question is, which is the best way to add generics?

Is there a design pattern particulary for this?

Now, while I’m not sure wrapping or extending is better, if this was a simple case I would have gone with one of them and not even considered doing both.

But, the CustomList is used everywhere, and I only want to replace it bit by bit.

Extending allows me to use the TypedCustomList as a CustomList, so that if I change where CustomList are being created to instead by TypedCustomList, later in code’s execution the code can still treat it like a CustomList.

But, I can’t treat a CustomList object as a TypedCustomList (even if I ensure the generic type is correct for that given CustomList). (Or am I missing how to do this, which would solve the problem?)

If a wrap it, I can now work with existing CustomLists, but I have to expose the internal CustomList object to pass it on to other code (for example, if I call a method expecting CustomList, I have to do instanceOfTypedCustomList._customList, I cannot pass instanceOfTypedCustomList).

If I wrap and extend it, I get take an existing CustomList and treat it like a TypedCustomList while still being able to treat my TypedCustomList as a CustomList. But, as you can see below, the ‘Both’ option looks the worst.

Extending

public class TypedCustomList<T> : CustomList
{
  public TypedCustomList()
    :base()
  {
  }

  public T getElementAt(int i)
  {
    return (T) base.getElementAt(i);
  }

  public void addElement(T element)
  {
    base.addElement(element);
  }

  ...ect.
}

Wrapping:

public class TypedCustomList<T>
{
  CustomList _customList { get; private set;}
  public TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    return (T) _customList.getElementAt(i);
  }

  public void addElement(T element)
  {
    _customList.addElement(element);
  }

  ...ect.
}

Both:

public class TypedCustomList<T> : CustomList
{
  private CustomList _customList;

  public TypedCustomList()
    :base()
  {
    _customList = null;
  }

  public TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    if(_customList == null)
    {
      return (T) base.getElementAt(i);
    }
    else
    {
      return (T) _customList.getElementAt(i);
    }
  }

  public void addElement(T element)
  {
    if(_customList == null)
    {
      base.addElement(element);
    }
    else
    {
      _customList.addElement(element);
    }
  }

  ...ect.
}

P.S.

More background which may be relevant to the problem.

There is one class that has a CustomList that is used all over the application, with different parts of the application with each instance having different object types (over a dozen in total). I want to eventually have this class have a unique TypedCustomList for every use. But until I can be sure that all references to it’s CustomList are gone, I wanted to add some error handling. So I was adding something like the following:

public ClassThatUsesCustomList
{
...
private CusotmList _list;
private TypedCustomList<SomeObject> _SomeObjectCustomList;

public CustomList list
{
    get
    {
      //Already existing code
      if(_list == null)
      {
        _list = new CustomList();
      }

      //My code
      catchMissedGetSet(_list);


      return _list;
    }
    set
    {
      catchMissedGetSet(value);
      _list = value;
    }
}

public SomeObjectCustomList
{
  get
  {
    if(_SomeObjectCustomList == null)
    {
      _SomeObjectCustomList = new TypedCustomList<SomeObject>();
    }

    return _SomeObjectCustomList;
  }
  set
  {
    _SomeObjectCustomList = value;
  }
}


private void catchMissedGetSet(CustomList cl)
{
  bool findMissedSpots = true;

  if(cl == null || cl.Count == 0 || cl[0] is SomeObject)
  {
    SomeObjectCustomList = new SomeObjectCustomList(cl);  //Using wrapping.
    if(findMissedSpots && System.Diagnostics.Debugger.IsAttached)
    {
      System.Diagnostics.Debugger.Break();  
      //Hey, you missed a place.  Use step out to find it.
    }
  }
}


...
}

I did this to catch any spots I missed and to avoid any bugs. It requires me wrapping it (as far as I can tell).

12

The answer is wrapping, but it is considerably more work than implied here. I see why you are trying to do this though, because after a certain size of the code base it indeed can be a nightmare to work with typecasting every time you call a library function. Subclassing CustomList is not advisable, as it would expose all the functions that return or expect an object. Having a public property as in the second example is, for the same reason, also unadvisable. I believe you are facing a situation similar to the following:

interface Producer
{
  CustomList produce();
}

interface Consumer
{
  void consume(CustomList list);
}

This is how I would wrap it:

public class TypedCustomList<T>
{
  private readonly CustomList _customList;
  internal CustomList customList
  {
    get { return _customList; }
  }

  internal TypedCustomList(CustomList cl)
  {
    _customList = cl;
  }

  public T getElementAt(int i)
  {
    return (T) _customList.getElementAt(i);
  }

  public void addElement(T element)
  {
    _customList.addElement(element);
  }

  ... ect.
}

The producer:

class TypedProducer<T>
{
  private readonly Producer producer = new Producer();
  public TypedCustomList<T> produce()
  {
    return new TypedCustomList<T>(producer.produce())
  }
}

The consumer:

class TypedConsumer<T>
{
  private readonly Consumer consumer = new Consumer();
  public void consume(TypedCustomList<T> list)
  {
    consumer.consume(list.customList);
  }
}

You will need to put the wrapping classes to their own assembly, so that they hide the internal parts.

I can safely suggest you this solution, which I beleive generally considered a good practice. You will need to wrap the subset of the library you are using in this manner.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật