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!

有帮助吗?

解决方案

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.

  1. 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.

  2. 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 TNameinsideSpecialCollectioN<>` 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>();
    }
    
  3. 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>();
    }
    

其他提示

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.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top