I have a class who requires the following definition :
public class Table<T> : ObservableCollection<T> where T : IRowDef, new()
I want to create a collection of it and map types with the instances. So I try :
public sealed class TableCollection : IEnumerable<Table<IRowDef>>
{
private Dictionary<Type, Table<IRowDef>> _tableDictionary;
public Table<IRowDef> GetTable<T>() where T : IRowDef, new()
{
Table<IRowDef> table = null;
if (_tableDictionary.ContainsKey(typeof(T)))
{
table = _tableDictionary[typeof(T)];
}
else
{
table = new Table<IRowDef>();
_tableDictionary.Add(typeof(T), table);
}
return table;
}
...
}
But I can't make it work. The following lines and several others gives the same error :
private Dictionary<Type, Table<IRowDef>> _tableDictionary;
The error, translated, tells IRowDef must be non abstract and have a parameterless constructor. I know it comes from the "new()" type restriction on the Table class definition, but it is required by the code inside this class. I known I could solve this by using a specific class type who would contains a parameter less constructor, for example :
private Dictionary<Type, Table<ClientTable>> _tableDictionary;
But different types of table must be supported and is the reason why all of them implements IRowDef.
Does anybody knows how I can solve this?
The problem is that you need a collection of tables, but a Table<X>
is not compatible with a Table<Y>
and a WhateverCollection<Table<X>>
is not compatible with a WhateverCollection<Table<Y>>
, even if X
is an interface type and Y
implements this interface.
Why it that? Asssume that you have
List<IAnimal> animals = new List<Elefant>();
animals.Add(giraffe); // Ooops!
Put that in your pipe and smoke it!
// DOES NOT WORK! T<Base> b = new T<Derived>(); // T<Derived> is not assignment compatible to T<Base>!!!
but
Base b = new Derived(); // OK
The trick is to have two table classes: One non-generic base class and a derived generic class:
public abstract class Table
{}
public class Table<T> : Table
where T : IRowDef, new()
{
private readonly ObservableCollection<T> _rows = new ...;
}
Now you can declare a
private Dictionary<Type, Table> _tableDictionary;
Or if you want to stick to deriving from the an observable collection, declare a (non-generic!) ITable
interface instead of a Table
base class and let Table<T>
implement ITable
then declare the dictionary as Dictionary<Type, ITable>
.
You could remove the new()
constraint and use Activator.CreateInstance<T>()
to create new objects. This moves the check from compile time to runtime. The C# compiler translates new T()
to a Activator.CreateInstance
call anyway.
Olivier Jacof-Descombes proposed one of possible approaches. The other one (applicable only if you can modify Table
class):
public interface ITable
{
//Some needed methods, f,e,
IRowDef GetSth();
}
then:
public class Table<T> : ..., ITable where T : IRowDef, new()
{
IRowDef ITable.GetSth()
{
return (IRowDef)this.GetSthImplInsideTable(); // cast is optional
}
public T GetSthImplInsideTable() { /* impl */ }
}
You could use it as:
private Dictionary<T, ITable> _tablesDict;
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.