C# 不是可分配类型 - 泛型

标签 c# generics polymorphism

所以我只是在研究我正在研究的状态机类型,主要是想尝试一下 Activator.CreateInstance 方法看看它是什么样的,但我遇到了一个我似乎无法使用的问题where我认为的条款。如果我只是个白痴并且每个人都笑我离开这里,我会提前道歉。所以我有 2 个小类。

public class TransitionContainer<TTransition, TStateTo> :
    ITransitionContainer<TTransition, TStateTo>
    where TTransition : ITransition
    where TStateTo : IState
{
    public TransitionContainer()
    {
        StateTo = typeof(TStateTo);
        Transition = Activator.CreateInstance<TTransition>();
    }

    public Type StateTo { get; private set; }

    public TTransition Transition { get; private set; }
}

还有

  public class StateContainer<T> : IStateContainer<T> where T : IState
{
    private Dictionary<Type, TransitionContainer<ITransition, IState>> _transitions =
        new Dictionary<Type, TransitionContainer<ITransition, IState>>();

    public StateContainer()
    {
        State = Activator.CreateInstance<T>();
    }

    public T State { get; private set; }

    public int TransitionCount
    {
        get { return _transitions.Count; }
    }


    public void AddTransition<TTransition, TStateTo>() where TTransition : ITransition, new()
        where TStateTo : IState, new()
    {
        var transitionContainer= new TransitionContainer<TTransition, TStateTo>();

        _transitions.Add(typeof(TTransition), transitionContainer);
    }

于是上线_transitions.Add(typeof(TTransition), transitionContainer);我收到 cannot convert TransitionContainer<TTransition,TStateTo> expression to type TransitionContainer<ITransition,IState>错误。

如果我将通用参数更改为

var transitionContainer= new TransitionContainer<ITransition, IState>();

它工作正常,但我想使用 new() 的继承类型,所以我可以确定我可以实例化它们。

如果我做错了什么,我再次道歉,我只是碰壁了,我的谷歌搜索没有把我引向正确的方向。我没有包含任何其他接口(interface)或类,因为它们似乎不是问题的一部分,但如果需要,我可以附加它们。感谢您的帮助!

最佳答案

出现这个问题是因为:

  1. ITransitionContainer不是 covariant interface在其类型参数上。
  2. AddTransition方法通用参数是 not constrainedreference types .
  3. _transitions不是 ITransitionContainer 的字典值,因此无需将其更改为 Dictionary<Type, ITransitionContainer<ITransition, IState>>我们仍然无法添加甚至适当限制的协变转换。

简化示例

考虑以下简化情况:

public interface ITransition
{

}

public class SomeTransition : ITransition
{

}

public interface ITest<TTransition>
    where TTransition : ITransition
{
    TTransition Value { get; }
}


public class SomeTest<TTransition> : ITest<TTransition>
    where TTransition : ITransition
{
    public TTransition Value
    {
        get
        {
            throw new NotImplementedException();
        }
    }
}

两者都会失败

public static void Do<TTransition>()
    where TTransition : ITransition
{
    ITest<ITransition> item = new SomeTest<TTransition>();
}

ITest<ITransition> item = new SomeTest<SomeTransition>();

如果你制作ITest协变

public interface ITest<out TTransition>

,那么它只会在泛型方法中失败。因为这里TTransition可以是结构和 co/(contra)variance doesn't work with value types :

public static void Do<TTransition>()
    where TTransition : ITransition
{
    ITest<ITransition> item = new SomeTest<TTransition>();
}

但是如果你使那个方法constrained to only reference types , 那么它在这两种情况下都有效:

public static void Do<TTransition>()
    where TTransition : class, ITransition
{
    ITest<ITransition> item = new SomeTest<TTransition>();
}

将相同的原则(outclass)应用于您的两个通用参数,它将完成工作。


针对您的特定案例的完整解决方案:

public interface IState
{    }

public interface ITransition
{    }

// !!!!! - Here we add out specifier
public interface ITransitionContainer<out TTransition, out TStateTo>
    where TTransition : ITransition
    where TStateTo : IState
{
    Type StateTo
    {
        get;
    }

    TTransition Transition
    {
        get;
    }
}

public interface IStateContainer<T> where T : IState
{
    T State
    {
        get;
    }
}


public class TransitionContainer<TTransition, TStateTo> : ITransitionContainer<TTransition, TStateTo>
    where TTransition : ITransition
    where TStateTo : IState
{
    public TransitionContainer()
    {
        StateTo = typeof(TStateTo);
        Transition = Activator.CreateInstance<TTransition>();
    }

    public Type StateTo { get; private set; }

    public TTransition Transition { get; private set; }
}


public class StateContainer<T> : IStateContainer<T> where T : IState
{
    private Dictionary<Type, ITransitionContainer<ITransition, IState>> _transitions =
        new Dictionary<Type, ITransitionContainer<ITransition, IState>>();

    public StateContainer()
    {
        State = Activator.CreateInstance<T>();
    }

    public T State { get; private set; }

    public int TransitionCount
    {
        get { return _transitions.Count; }
    }

    public void AddTransition<TTransition, TStateTo>()
        // !!!!!! - Here we add class constraints
        where TTransition : class, ITransition, new()
        where TStateTo : class, IState, new()
    {
        var transitionContainer = new TransitionContainer<TTransition, TStateTo>();

        _transitions.Add(typeof(TTransition), transitionContainer);
    }
}

关于C# 不是可分配类型 - 泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38035427/

相关文章:

c# - 如何在不使用预制件的情况下以编程方式创建 Sprite ?

c# - CultureInfo.Region 在立即窗口中工作,而不是在代码中工作

.NET 4.0 : How can I get the underlying type of a generic parameter if it is Nullable?

c# - 如何在封闭泛型类型上获取泛型方法,从开放泛型类型打开 MethodInfo?

java - Jackson:如何在运行时使用泛型解码到类?

c# - 用年份填充组合框

c# - 如何允许用户输入 Value1 然后说 Value1 = Value2

c++ - std::vector 类型引用的无效初始化

php - 在 Laravel Eloquent 中检索所有 morphedByMany 关系

C# 从工厂返回通用接口(interface)