2

我有一个小类,它实现了一个字典,该字典从接口的类型映射到从基类扩展的接口的实现。可惜抽象基类并没有实现接口,所以一旦在字典中,似乎没有办法将两者联系起来。这个类中还有另一种方法,它依赖于将对象存储为 BaseClass(事实上,我的大部分类都依赖于它——字典中的 getter 有点方便)。

private readonly Dictionary<Type, BaseClass> dictionary;

public void Add<T>(BaseClass base)
{
    if (!(base is T))  // How to get rid of this check?
    {
        throw new ArgumentException("base does not implement " + typeof(T).Name);
    }

    this.dictionary.Add(typeof(T), base);
}

public T Get<T>()
{
    BaseClass base;
    this.dictionary.TryGetValue(typeof(T), out base);
    return (T)(object)base;  // How to get rid of (object) cast?
}

是否有任何聪明的约束可以用来删除 (base is T) 检查、强制转换为对象或两者兼而有之?

这是课程设置,供参考:

class BaseClass { }
interface IThing { }
class MyClass : BaseClass, IThing { }

dict.Add<IThing>(new MyClass());
IThing myClass = dict.Get<IThing>();
4

2 回答 2

1

获得您正在寻找的编译时强制执行的唯一方法是,如果您具有正在添加的派生类型的编译类型知识。

例如,如果您还为要添​​加的类指定类型参数,那么您可以约束该类实现接口类型参数:

    public void Add<TInterface, TClass>(TClass @base)
        where TClass : BaseClass, TInterface {
        this.dictionary.Add(typeof(TInterface), @base);
    }

所以你可以这样做:

    MyClass ok = new MyClass();
    dict.Add<IThing, MyClass>(ok);

但不是这个:

    class MyClassNotIThing : BaseClass { }

    MyClassNotIThing notOk = new MyClassNotIThing();
    dict.Add<IThing, MyClassNotIThing>(notOk);

除此之外,泛型约束不提供约束已知类型(即BaseClass)从泛型类型参数继承的方法。

于 2013-07-12T01:42:04.367 回答
0

这是我最终使用的解决方案。有一些技巧可以在没有检查的情况下使 Add() 安全(请参阅 cokeman19 答案的评论中的链接),但我选择不这样做,因为我发现这段代码更干净一些。

interface IThing { }

abstract class BaseClass
{
    internal T AsInterface<T> where T : class
    {
        return this as T;
    }
}

class MyClass : BaseClass, IThing { }

class DictionaryClass
{
    private readonly Dictionary<Type, BaseClass> dictionary;

    public void Add<T>(BaseClass base)
    {
        if (base is T)
        {
            dictionary.Add(typeof(T), base);
        }
    }

    public T Get<T>() where T : class
    {
        return dictionary[typeof(T)].AsInterface<T>();
    }
}

请注意,此解决方案确实允许以下调用:

myClass.AsInterface<IThingItDoesntImplement>() 

但这返回 null 并且我将函数设为内部以防止奇怪的使用。

于 2013-07-12T17:52:23.840 回答