如果有人有任何想法,我很难过。我有通用方法
public void Foo<TClass>(TClass item) where TClass : class
{ }
我想从另一个泛型方法调用此方法,但是这个泛型方法没有类型约束“where TClass:class”
public void Bar<T>(T item)
{
this.Foo<T>(item);
}
这不起作用,我收到错误
“类型'T'必须是引用类型才能将其用作参数'TClass'”
我理解。但我的问题是 - 我可以用C#语法做什么来“过滤”泛型类型“T”,如果它是一个类,则将它传递给“this.Bar”。像......那样......
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo<T **as class**>();
}
我意识到我可以使用反射来调用Foo,但这似乎就像是作弊。我可以用C#在运行时使用约束传递“T”吗?
另外 - 我无法更改方法“Bar”的约束,因为它来自一个接口,所以约束必须匹配接口上的约束
答案 0 :(得分:4)
不幸的是,如果不将Bar
更改为具有通用约束class
或使用反射,则无法执行此操作。为了编译C#,必须在编译时知道T
确实是class
值。无法使用typeof(T).IsClass
之类的动态测试来满足此编译时约束。
你在问题中提到你不能改变Bar
,但似乎你愿意接受动态失败的可能性。也许改为将Foo
更改为没有约束,而是在T
不是类类型时抛出异常
答案 1 :(得分:4)
在没有反射的情况下调用Foo
的唯一方法是将item
强制转换为其层次结构中的某个类型/类(在正确的IsClass
检查之后)。
显然,在层次结构中只有一种类型,你知道先验:Object
。
public void Bar<T>(T item)
{
if (typeof(T).IsClass)
this.Foo((object) item);
}
编辑:
此外,在您说的其中一条评论中,您添加了class
约束来实例化T
。您不需要,您需要的是new
constraint。
答案 2 :(得分:0)
if (typeof(T).IsClass)
{
this.GetType()
.GetMethod("Foo", System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.Public)
.Invoke(this, new object[] { item });
}
答案 3 :(得分:-1)
我相信没有办法让它编译。您将不得不使用反射来进行呼叫。
实际上。如果你在一个类中包含它,你可以作弊:
public class Container<T>
{
public Container(T value)
{
Value = value;
}
public T Value { get; private set; }
}
public void Bar<T>(T item)
{
this.Foo<Container<T>>(new Container<T>(item));
}
但是这会增加一个你需要调用的图层,并使类型不那么清晰。