Generic Bug or Limitation or By Design?

The following is my code
Common
 public abstract class DataFieldBase
 {
  public DataFieldCollection<DataFieldBase> Parent;
  public string FieldName;
  protected object BaseValue;  

  public DataFieldBase(string fieldName, object value)
  {
   this.FieldName = fieldName;
   this.BaseValue = value;
  }
 }

 public class StringField : DataFieldBase
 {
  public StringField() : base("StringField", "Test") { }

  public object Value
  {
   get { return this.BaseValue; }
   set { this.BaseValue = value; }
  }
 }

 public class ReadOnlyField : DataFieldBase
 {
  public ReadOnlyField() : base("ReadOnlyField", System.Guid.NewGuid()) { }

  public object Value
  {
   get { return this.BaseValue; }
  }

Sample A
I cannot assign a parent(DataFieldCollection) to child
Compile error (Cannot implicitly convert type 'ConsoleApplication1.DataFieldCollection<T>' to 'ConsoleApplication1.DataFieldCollection<ConsoleApplication1.DataFieldBase>')

 class Program
 {

  static void Main(string[] args)
  {
   DataFieldCollection<DataFieldBase> dataFields = new DataFieldCollection<DataFieldBase>();
   StringField stringField = new StringField();
   ReadOnlyField readOnlyField = new ReadOnlyField();

   dataFields.Add(stringField);
   dataFields.Add(readOnlyField);

  }

 }

 public class DataFieldCollection<T> where T : DataFieldBase
 {
  private Dictionary<string, T> _collection = new Dictionary<string, T>();

  public DataFieldCollection() { }

  public void Add(T field)
  {
   field.Parent = this;
   this._collection.Add(field.FieldName, field);
  }

  public T Get(string fieldName)
  {
   return this._collection[fieldName];
  }
 }

Sample B
I can compile.

 class Program
 {

  static void Main(string[] args)
  {
   DataFieldCollection<DataFieldBase> dataFields = new DataFieldCollection<DataFieldBase>();
   StringField stringField = new StringField();
   ReadOnlyField readOnlyField = new ReadOnlyField();

   stringField.Parent = dataFields;
   dataFields.Add(stringField);
   readOnlyField.Parent = dataFields;
   dataFields.Add(readOnlyField);

  }

 }

 public class DataFieldCollection<T> where T : DataFieldBase
 {
  private Dictionary<string, T> _collection = new Dictionary<string, T>();

  public DataFieldCollection() { }

  public void Add(T field)
  {
   this._collection.Add(field.FieldName, field);
  }

  public T Get(string fieldName)
  {
   return this._collection[fieldName];
  }
 }

Why Sample A cannot

Please help me




Answer this question

Generic Bug or Limitation or By Design?

  • Yel

    Thank you for your reply.
    It can solve my problem in your approach 1 but it will lose parent default interface when implement.  For example.
    public interface IParent
    {
         string ID{ get;}
    }

    public class DataFieldCollection<T> : IParent where T : DataFieldBase {
       public DataFieldCollection(){}
       public void Add(T Field){}
       public string ID
       {
          get { return "ABC"; }   
       }   
    }


    static void Main(string[] args)
    {
       ......
         dataFields.Add(stringField);
         ((DataFieldCollection<DataFieldBase ) stringField.Parent).Add(...)
    }

    It will casting again...that you know one of the benefit of generic is reducing to casting

    And your approach 2 that it cannot be compiled
    (The type 'T' must be convertible to 'ConsoleApplication1.DataFieldBase<T>' in order to use it as parameter 'T' in the generic type or method 'ConsoleApplication1.DataFieldCollection<T>')


  • DMOORE

    Thank you for you repley

    I think this approach not suitable for me.  In your approach that I will lose dirrect reference.  For example If DataFieldCollection add a Readonly field the memberwiseClone will clone this field

    dataFields.ReadOnly=false;
    dataFields.Add(AField);
    Now AField.Parent.ReadOnly is false;

    If I changed dataFields.ReadOnly=true, the AField.Parent.ReadOnly still is false;

    If this is not a bug I think generic is not useful for me that I think this is general design structure.  In this design child added into the collection that the collection will notify which parent is collection.  If sample A cannot do that I will give up generic approach in this design.  I will change the design to the following

    public class DataFieldCollection
     {
      private Dictionary<string, DataFieldBase> _collection = new Dictionary<string, DataFieldBase>();

      public DataFieldCollection() { }

      public void Add(DataFieldBase field)
      {
       this._collection.Add(field.FieldName, field);
      }

      public DataFieldBase Get(string fieldName)
      {
       return this._collection[fieldName];
      }
     }

    In this design I will alway casting when get it for example
      static void Main(string[] args)
      {
       DataFieldCollection dataFields = new DataFieldCollection();
       StringField stringField = new StringField();

       dataFields.Add(stringField);

       stringField = (stringField) dataFields.Get(stringField.FieldName);
      }



  • neuralsea8

    Hi, from your example, I can not see how your using the Parent property, so I'm not sure if this will work for you, but you can work around your issue as follows:



    public interface IParent {...}
    public class DataFieldCollection<T> : IParent where T : DataFieldBase {...}
    public abstract class DataFieldBase
    {
    public IParent Parent;
    ...
    }

     


    OR



    public abstract class DataFieldBase<T>
    {
    public DataFieldCollection<T> Parent;
    ...
    }

     


  • aschreiber2

    As with all development there are tradeoffs.  I thought of the problem with the second solution after I left for my weekend trip.  There are ways of making it work, but I still am not sure of what you want to accomplish.  Is it your intention that a collection can only contain one type of data field (i.e. StringField )  If so, here's a solution.  If not, then using Generics for the collection is a mistake, and you are going to have to do casting.



    public class DataFieldCollection<T1,T2>
       where T1 : DataFieldBase<T2>
    {...}

    public abstract class DataFieldBase<T>
    {
    public DataFieldCollection<DataFieldBase<T>,T> Parent ;
    ...
    }


     



  • Graham Parker


              public void Add(T field)         {             field.Parent = (DataFieldCollection <DataFieldBase> ) this.MemberwiseClone() ;             this._collection.Add(field.FieldName, field) ;         }  
     


    if u cast like this, it works well..
    so its not bug.. try like this


  • Generic Bug or Limitation or By Design?