簡體   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