C#不可分配类型 - 泛型 [英] C# Is Not Assignable Type - Generics
问题描述
所以我只是用我正在研究的状态机类型进行攻击,并且主要想试用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()的继承类型,所以我可以确定我可以实例化它们。
我再次道歉,如果我做了一件令人难以置信的错误的事情,我只是碰到一堵砖墙,并且我的谷歌搜索导致我没有任何好处方向。我没有包含任何其他接口或类,因为它们似乎不是问题的一部分,但如果需要,我可以附加它们。感谢您的帮助!
出现此问题的原因是:
-
ITransitionContainer
不是协变接口的类型参数。 -
AddTransition
方法泛型参数是不是约束为参考类型。
-
_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:
ITransitionContainer
is not a covariant interface over its type arguments.
AddTransition
method generic arguments are not constrained to be reference types.
_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屋!