繁体   English   中英

C#不可分配类型 - 泛型

[英]C# Is Not Assignable Type - Generics

所以我只是在处理我正在处理的状态机类型,并且大多想要尝试使用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()的继承类型,所以我可以确定我可以实例化它们。

我再次道歉,如果我做了一件令人难以置信的错事,我只是碰到了一堵砖墙而且我的谷歌搜索引导我走向了不好的方向。 我没有包含任何其他接口或类,因为它们似乎不是问题的一部分,但如果需要我可以附加它们。 谢谢你的帮助!

出现此问题是因为:

  1. ITransitionContainer不是其类型参数的协变接口
  2. AddTransition方法通用参数被不限制引用类型
  3. _transitions不是具有ITransitionContainer值的字典,因此如果不将其更改为Dictionary<Type, ITransitionContainer<ITransition, IState>>我们仍然无法添加正确的resticted协变转换。

简化示例

考虑以下简化案例:

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)方差不适用于值类型

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

但是如果你将该方法限制为仅引用类型 ,那么它将在两种情况下都有效:

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);
    }
}

这失败了,因为泛型不是协变的。 问题可以在这里看到:

TransitionContainer<ITransition, IState> value = new TransitionContainer<TTransition, TStateTo>();

这给你同样的错误。 您还可以通过以下简单方法获得此错误:

List<IComparable> list = new List<DateTime>();

Visual Studio告诉你(基本上):

Cannot implicitly convert type 'List<System.DateTime>' to 'List<System.IComparable>'

你需要做的是转换对象。 您可以创建一个Convert方法,该方法返回TransitionContainer<ITransition, IState> ,然后使用.Add(typeof(TTransition), transitionContainer.Convert()) (或者您命名的任何名称)。

但最无痛的选择是通过添加此静态方法为TransitionContainer<TTransition, TStateTo>对象创建隐式转换:

public static implicit operator TransitionContainer<ITransition, IState>(TransitionContainer<TTransition, TStateTo> value)
{
    return new TransitionContainer<ITransition, IState>() { StateTo = value.StateTo, Transition = value.Transition };
}

就是这样。 :)

当然,你必须复制它工作所需的一切,在这种情况下,似乎这两个对象就足够了。

暂无
暂无

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

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