如何在不指定Key类型的情况下定义泛型类型的KeyedCollection

时间:2015-03-12 10:11:19

标签: c# .net vb.net generics .net-4.5

我有一个具有指定键类型的泛型类,我想创建该类的KeyedCollection(Of。我认为代码更清楚我的话 问题是是否可以重写代码以便可以在不指定键类型(int或整数)的情况下定义MyEnities

C#

public abstract class Entity<TPrimKey>
{public abstract TPrimKey Key { get; set; }    }

public class Entities<TPrimKey, TItem> : ObjectModel.KeyedCollection<TPrimKey, TItem> 
                       where TItem : Entity<TPrimKey>
{
    protected override TPrimKey GetKeyForItem(TItem item)
    {return item.Key;}
}

public class MyEntity : Entity<int>
{
    public override int Key { get; set; }
}

public class MyEnities : Entities<int, MyEntity>
{}

VB

Public MustInherit Class Entity(Of TPrimKey)
   Public MustOverride Property Key As TPrimKey
End Class

Public Class Entities(Of TPrimKey, TItem As Entity(Of TPrimKey))
    Inherits ObjectModel.KeyedCollection(Of TPrimKey, TItem)
    Protected Overrides Function GetKeyForItem(item As TItem) As TPrimKey
        Return item.Key
    End Function
End Class

Public Class MyEntity
    Inherits Entity(Of Integer)
    Public Overrides Property Key As Integer
End Class

Public Class MyEnities
    Inherits Entities(Of Integer, MyEntity)
End Class

1 个答案:

答案 0 :(得分:0)

你几乎拥有它。这是一个解决方案:

using System.Collections.ObjectModel;

public class Entity<TPrimKey>
{
    public TPrimKey Key { get; set; }
}

public class Entities<TPrimKey> : KeyedCollection<TPrimKey, Entity<TPrimKey>>
{
    protected override TPrimKey GetKeyForItem( Entity<TPrimKey> item )
    { return item.Key; }
}

public class MyEntity1 : Entity<int>
{
}

public class MyEntity2 : Entity<int>
{
}

public class MyEntities : Entities<int>
{
    public static void Test()
    {
        var entities = new MyEntities();

        var entity1 = new MyEntity1();
        entities.Add( entity1 );

        var entity2 = new MyEntity2();
        entities.Add( entity1 );
    }
}

要清楚,这是一种略微不同的思考目标的方式。 MyEntities仍指定密钥类型int;您想要的任何通用方法都会进入Entities<TPrimKey>。或者您在 MyEntitiesA<TPrimKey>Entities之间创建了一个通用类MyEntities ,以保存这些方法:

public abstract class MyEntitiesA<TPrimKey> : Entities<TPrimKey>
{
    // Methods that apply to all TPrimKeys go here.
    // Some methods may need to be abstract, and implemented
    // in each subclass, that has a concrete key (or at least a key with a constraint).
}

public class MyEntities : MyEntitiesA<int>
...

MyEntitiesA<TPrimKey>满足您的要求,而不指定键类型int 。 (在某些时候,您将创建具有特定类型的类和/或变量声明;“目标”是能够保持通用所有方法的通用。)

你缺少的是这一行:

    public class Entities<TPrimKey> : KeyedCollection<TPrimKey, Entity<TPrimKey>>

在那里,值的类型是根据键的类型定义的。这样,您就可以定义GetKeyForItem,使其适用于所有 TPrimKey

请注意,我已经包含了源自Entity<int>两个类,以显示此集合的全部功能。同时Test()显示它的实际效果。

您可能还会发现这些相关链接:
"Generic constraint to match numeric types"
use "where TPrimKey : class"
"Blind Interfaces to Models"

如果将集合基于interface而不是基类,则此技术更加强大。这允许任何支持正确接口(在该键类型上)的类被添加到集合中。在这里,我们看到这允许我们定义泛型EntityA<TPrimKey>EntityB<TprimKey>,以及它们的各种子类:

using System.Collections.ObjectModel;

public interface IEntity<TPrimKey>
{
    TPrimKey Key { get; set; }
}

public class Entities<TPrimKey> : KeyedCollection<TPrimKey, IEntity<TPrimKey>>
{
    protected override TPrimKey GetKeyForItem( IEntity<TPrimKey> item )
    { return item.Key; }
}

public class EntityA<TPrimKey> : IEntity<TPrimKey>
{
    public TPrimKey Key { get; set; }
}

public class MyEntityA1 : EntityA<int>
{
}

public class MyEntityA2 : EntityA<int>
{
}

public class EntityB<TPrimKey> : IEntity<TPrimKey>
{
    public TPrimKey Key { get; set; }
}


public class MyEntityB1 : EntityB<int>
{
}

public class MyEntities : Entities<int>
{
    public static void Test()
    {
        var entities = new MyEntities();

        var entityA1 = new MyEntityA1();
        entities.Add( entityA1 );

        var entityA2 = new MyEntityA2();
        entities.Add( entityA2 );

        var entityB1 = new MyEntityB1();
        entities.Add( entityB1 );
    }
}

注意:您不必转到 interface 来创建多个通用子类EntityAEntityB。我只是说,如果你开始变得那么复杂,那么就应该考虑定义一个接口,这样你就不会被“装箱”到一个基类。如果需要,定义一个接口可以很容易地重构类层次结构。