public interface IRule <T>
{
T Execute();
}
public class Rule : IRule<int>
{
public int Execute()
{
return 10;
}
}
IRule<int> rule = new Rule();
var genericRule = (IRule<object>) rule;
//Exception has occurred: CLR/System.InvalidCastException An exception of ype 'System.InvalidCastException' occurred in test.dll but was not handled in user code: 'Unable to cast object of type 'test.GenericCasting.Rule' to type test.GenericCasting.IRule`1[System.Object]'.'
在业务逻辑中,我需要通过反射来加载所有Rule对象,并且不了解Rule对象中使用的类型。知道如何解决这个问题吗?
答案 0 :(得分:2)
要在您的示例中执行类型转换,必须满足两个条件:
IRule<T>
必须是协变的,即IRule<out T>
T
的情况,也就是说,不能将int
用于T
,但是可以使用string
。一个工作示例:
public interface IRule <out T>
{
T Execute();
}
public class Rule : IRule<string> // T must be a reference type
{
public string Execute()
{
return "10";
}
}
//....
IRule<string> rule = new Rule();
var genericRule = (IRule<object>) rule;
正如@Servy正确地提到的那样,我解释了为什么原始代码不起作用,但没有解释如何解决原始问题。
方法如下:
// define a separate interface for non-typed invocation
public interface IRule
{
object ExecuteGeneric();
}
public interface IRule<T> : IRule
{
T Execute();
}
// every rule implements both typed and non-typed invocation interface
public class Rule : IRule<int>
{
public int Execute()
{
return 10;
}
object IRule.ExecuteGeneric()
{
return Execute();
}
}
//.....
IRule<int> rule = new Rule();
IRule genericRule = rule;
// perform non-typed invocation on rules of any T
var genericResult = genericRule.ExecuteGeneric();
答案 1 :(得分:2)
T=None
不是IRule<object>
的基本类型,因此强制类型转换无效。
从.NET 4接口开始可以标记为协变,但只能在特殊情况下使用:泛型参数必须仅在输出位置(返回值)中使用,并且只能将引用类型强制转换为彼此。在您的情况下,第一个条件得到满足,但第二个条件没有满足。
在这种情况下,可能的解决方案是引入非通用基类型。例如,这也可以将未知类型参数的IRule<int>
用作List<T>
。
IList
实施:
public interface IRule
{
object Execute();
}
public interface IRule<T> : IRule
{
new T Execute();
}
现在这将起作用:
public class Rule : IRule<int>
{
// this will be the public implementation (preferred way)
public int Execute() => 42;
// the nongeneric implementation if the object is cast to IRule
object IRule.Execute() => Execute();
}