C#不可分配类型 - 泛型 [英] C# Is Not Assignable Type - Generics

查看:129
本文介绍了C#不可分配类型 - 泛型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

所以我只是用我正在研究的状态机类型进行攻击,并且主要想试用Activator.CreateInstance方法来查看它是什么样的,并且遇到了一个我无法使用的问题其中子句,我会认为。如果我只是一个白痴,我会提前道歉,所有人都会把我从这里带出来。所以我有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;私人设置; }

public TTransition Transition {get;私人设置; }
}

以及

  public class StateContainer< T> :IStateContainer< T> 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;私人设置; }

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


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

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

$ / code>

因此,在 _transitions.Add(typeof( TTransition),transitionContainer); 我收到一个无法转换TransitionContainer< TTransition,TStateTo>表达式类型TransitionContainer< ITransition,IState> 错误。



如果我将通用参数更改为

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

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



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

解决方案

出现此问题的原因是:


  1. ITransitionContainer 不是协变接口的类型参数。

  2. AddTransition 方法泛型参数是不是约束参考类型
  3. _transitions 不是带有 ITransitionContainer 值的字典,因此,如果不将它更改为 Dictionary< Type,ITransitionContainer< ITransition,IState>>< / code>,我们仍然无法添加合适的协变转换。 b $ b



简化示例



请考虑以下简化情况:

  public interface ITransition 
{

}

公共类SomeTransition:ITransition
{

}

公共接口ITest< TTransition>
其中TTransition:ITransition
{
TTransition Value {get; }
}


公共类SomeTest< TTransition> :ITest< TTransition>
其中TTransition:ITransition
{
public TTransition Value
{
get
{
throw new NotImplementedException();





它会在

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

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

如果您制作 ITest 协变

  public interface ITest< out TTransition> 

,那么它只会在通用方法中失败。因为这里 TTransition 可以是一个struct和co /(contra)方差不会使用值类型

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

但是,如果您使该方法仅限于引用类型,那么它将起作用在这两种情况下:

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

$ / code>

应用相同的原则( out class )添加到您的两个泛型参数中,它将完成这项工作。




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

  public interface IState 
{}

public interface ITransition
{}

// !!!!! - 这里我们添加说明符
public interface ITransitionContainer< out TTransition,out TStateTo>
其中TTransition:ITransition
其中TStateTo:IState
{
类型StateTo
{
get;
}

TTransition转换
{
get;
}
}

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


公共类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;私人设置; }

public TTransition Transition {get;私人设置; }
}


public class StateContainer< T> :IStateContainer< T> 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;私人设置; }

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

public void AddTransition< TTransition,TStateTo>()
// !!!!!! - 这里我们添加类约束
其中TTransition:class,ITransition,new()
其中TStateTo:class,IState,new()
{
var transitionContainer = new TransitionContainer< TTransition ,TStateTo>();

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


So I'm just hacking around with a state machine type I was working on and mostly wanting to just try out the Activator.CreateInstance method to see what it was like, and I ran into a problem where I cant seem to use the where clause as I would think. I apologize ahead of time if I am just an idiot and everyone laughs me out of here. So I have 2 small classes.

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

as well as

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

So on the line _transitions.Add(typeof(TTransition), transitionContainer); I receive a cannot convert TransitionContainer<TTransition,TStateTo> expression to type TransitionContainer<ITransition,IState> error.

If I change the generic parameters to

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

it works fine, but I wanted to use inherited types that are new() so I could be sure I could instantiate them.

Again I apologize if I'm doing something incredibly wrong, I was just kind of ran into a brick wall and my googling led me in no good direction. I didnt include any of the other interfaces or classes as they didn't seem to be part of the problem, but if there needed I can attach them. Thanks for any help!

解决方案

This issue happens because:

  1. ITransitionContainer is not a covariant interface over its type arguments.
  2. AddTransition method generic arguments are not constrained to be reference types.
  3. _transitions is not a dictionary with ITransitionContainer values, so without changing it to Dictionary<Type, ITransitionContainer<ITransition, IState>> we still won't be able to add even properly resticted covariant transtions.

Simplified example

Consider the following simplified case:

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

It will fail in both

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

and

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

If you make ITest covariant

public interface ITest<out TTransition>

, then it will fail only in generic method. Because here TTransition can be a struct and co/(contra)variance doesn't work with value types:

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

But if you make that method constrained to only reference types, then it will work in both cases:

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

Apply the same principle(out and class) to your two generic arguments and it will do the job.


Full solution for your specific case:

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#不可分配类型 - 泛型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆