简体   繁体   English

通用约束,允许从接口到实现的转换

[英]Generic Constraint to allow casting from interface to implementation

I have a small class that implements a dictionary that maps from the type of an interface to an implementation of that interface that extends from a base class. 我有一个小类,该类实现一个字典,该字典从接口的类型映射到从基类扩展的该接口的实现。 Unfortunately the abstract base class does not implement the interfaces, so once in the dictionary, there seems to be no way to associate the two. 不幸的是,抽象基类没有实现接口,因此一旦进入字典,似乎就无法将两者关联。 There is another method in this class that is dependent on storing the objects as BaseClass (in fact, most of my class is dependent on that--the getter into the dictionary is somewhat of a convenience). 该类中还有另一种方法依赖于将对象存储为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?
}

Are there any clever constraints I can use to remove the (base is T) check, the cast to object, or both? 我是否可以使用任何巧妙的约束来删除(基数为T)检查,是否强制转换为对象,或两者都取消?

Here is the class setup, for reference: 这是类设置,以供参考:

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

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

The only way to get the compile-time enforcement you're looking for would be if you have compile-type knowledge of the derived type being added. 获得所需的编译时强制执行的唯一方法是,如果您具有要添加的派生类型的编译类型知识。

For example, if you also specify a type parameter for the class being added then you could constrain that the class implement the interface type parameter: 例如,如果还为要添加的类指定类型参数,则可以约束该类实现接口类型参数:

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

So you could do this: 因此,您可以这样做:

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

But not this: 但这不是:

    class MyClassNotIThing : BaseClass { }

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

Aside from that, generic constraints don't offer a means by which to constrain that a known type (ie BaseClass ) inherit from a generic type parameter. 除此之外,泛型约束没有提供一种方法来约束已知类型(即BaseClass )从泛型类型参数继承。

Here is the solution I ended up using. 这是我最终使用的解决方案。 There are a few tricks that can make the Add() safe without the check (see the link in a comment to cokeman19's answer), but I opted not to do that as I find this code a bit cleaner. 有一些技巧可以使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>();
    }
}

Note that this solution does allow calls like: 请注意,此解决方案确实允许像这样的调用:

myClass.AsInterface<IThingItDoesntImplement>() 

but this returns null and I made the function internal to prevent strange uses anyway. 但这返回null,并且我将函数设为内部函数以防止反正使用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM