Reputation: 63
I need implement a collection (for example, SpecCollection
) which should contain KEY
and VALUE
. The key should be a composite key. Please see the short implementation:
public class CompositeKey<TId, TName>
{
private TId _id;
private TName _name;
public TId Id { get; set; }
public TName Name { get; set; }
}
I should initialize my collections only by the following way:
SpecialCollection<CompositeKey<string, int>, DateTime> e = new
SpecialCollection<CompositeKey<string, int>, DateTime>();
or like this:
SpecialCollection<CompositeKey<DateTime, int>, SomeClass> e = new
SpecialCollection<CompositeKey<DateTime, int>, SomeClass>();
Please let me know how can I declare my collection if it is possible?
I have found the following way:
public class SpecialCollection<TId, TName, TValue>
: Dictionary<CompositeKey<TId, TName>, TValue>
{
private Dictionary<CompositeKey<TId, TName>, TValue> _baseDictionary = new
Dictionary<CompositeKey<TId, TName>, TValue>();
}
But in this case I can initialize the collection object only like this:
SpecialCollection<DateTime, int, string> col =
new SpecialCollection<DateTime, int, string>();
Do you have any ideas how to declare the collection?
Thanks!
Upvotes: 1
Views: 301
Reputation: 1628
Maybe you're looking for something like this:
public class SpecialCollection<TKey, TValue> : Dictionary<TKey, TValue>
where TKey : CompositKey
{
}
public abstract class CompositeKey
{
protected CompositeKey(object id, object name)
{
Id = id;
Name = name;
}
public object Id { get; private set; }
public object Name { get; private set; }
}
public class CompositeKey<TId, TName> : CompositeKey
{
public CompositeKey(TId id, TName name)
: base(id, name) { }
public new TId Id
{
get { return (TId)base.Id; }
}
public new TName Name
{
get { return (TName)base.Name; }
}
}
The abstract non generic CompositeKey
class gives you a limited access to your Id
and Name
property in your SpecialCollection
class.
But I think you should consider your first thought, because then you have the type safety you maybe need on Id
and Name
.
Upvotes: 1
Reputation: 13696
There's no way to do exactly what you want - the .NET compiler can't partially intuit type parameters for generics. This leaves you with three choices.
Do nothing. The way you have it working now is the standard way to implement something like this. You get the key type you want (CompositeKey<Tid, TName>
) automatically.
Give up the types of CompositeKey<>
. In this scenario, you accept any CompositeKey
as a TKey
value. To do this, you need either a non-generic base class for CompositeKey
or an ICompositeKey
interface. You will be unable to access the types of the Tid
and TNameinside
SpecialCollectioN<>` though, because you're not specifying any types it can use.
public class SpecialCollection<TKey, TValue>
: Dictionary<TKey, TValue> where TKey : CompositeKey
{
private Dictionary<TKey, TValue> _baseDictionary = new
Dictionary<TKey, TValue>();
}
Specify four type parameters. In this way, you force the first type to be a CompositeKey<Tid, TName>
, and the SpecialCollection<>
will know what the types of it are. On the other hand, you have to specify all four, because C# can't do partial generic type inference. (i.e. it's all or nothing). Note that you can change the order around to whatever makes the most sense to you.
public class SpecialCollection<TKey, TValue, Tid, TName>
: Dictionary<TKey, TValue> where TKey : CompositeKey<Tid, TName>
{
private Dictionary<TKey, TValue> _baseDictionary = new
Dictionary<TKey, TValue>();
}
Upvotes: 4