从类型T访问属性

时间:2012-07-23 08:17:18

标签: c# generics

我有一个缓存类,它将列表存储到字典中:

public class CacheList<T>
{
    private Dictionary<UInt64, T> _cacheItems = new Dictionary<UInt64, T>();

    public IList<T> GetItems()
    {
        return new List<T>(_cacheItems.Values);
    }

    public void Add(T item)
    {
        UInt64 key = (UInt64)(item.GetHashCode());

        if (!_cacheItems.ContainsKey(key))
            _cacheItems.Add(key, item);
    }
}

现在我通过从泛型T中获取Hashcode来向字典添加项目。但是我想指定我想要哪个字段/属性作为键。问题是它是一个类型T,所以它不知道这个项目中有哪些属性。

如何从通用项目访问属性?

3 个答案:

答案 0 :(得分:2)

我看到了仿制品和思想“约束”,但事后我更喜欢Marc's approach,所以我会走他的路。

您可以创建一个接口,公开您需要的属性,然后约束该接口:

interface IExposeKey
{
    string Key { get; }
}

public class CacheList<T> where T : IExposeKey { }

在代码中,编译器现在可以假设TIExposeKey,因此可以提供强类型访问:

public void Add(T item)
{
    string key = item.Key;

    if (!_cacheItems.ContainsKey(key))
        _cacheItems.Add(key, item);
}

您甚至可以以这种方式公开属性名称,然后在T实例上使用反射,但是您为运行时错误打开了大门。

答案 1 :(得分:2)

也许:

public class CacheList<T, TKey>
{
    private readonly Dictionary<TKey, T> _cacheItems = new Dictionary<TKey, T>();
    private readonly Func<T, TKey> selector;
    public CacheList(Func<T, TKey> selector)
    {
        this.selector = selector;
    }
    public IList<T> GetItems()
    {
        return new List<T>(_cacheItems.Values);
    }

    public bool Add(T item)
    {
        TKey key = selector(item);

        if (_cacheItems.ContainsKey(key)) { return false; }

        _cacheItems.Add(key, item);
        return true;
    }
    public bool TryGetValue(TKey key, out T value)
    {
        return _cacheItems.TryGetValue(key, out value);
    }
}

然后:

var dict = new CacheList<Customer,int>(c => c.CustomerId);

答案 2 :(得分:2)

您可以使用lambda函数指定密钥。像这样:

public class CacheList<T, P>
{
    private Dictionary<P, T> _cacheItems = new Dictionary<P, T>();
    private Func<T, P> _getKey;

    public CacheList(Func<T, P> getKey)
    {
        _getKey = getKey;
    }

    public IList<T> GetItems()
    {
        return new List<T>(_cacheItems.Values);
    }

    public void Add(T item)
    {
        P key = _getKey(item);

        if (!_cacheItems.ContainsKey(key))
            _cacheItems.Add(key, item);
    }
}

然后您将创建如下的实例:

var cl = new CacheList<MyClass, string>(x => x.SomeProperty);

这对你有用吗?