我有两个班级,BaseClass
和Person
。 Person
类继承自BaseClass
。然后我使用以下通用方法。
public static PropertyInfo GetProperty<T>(T item, Func<PropertyInfo, bool> predicate)
{
return GetProperty(typeof(T), predicate);
}
在BaseClass
我有一个调用GetProperty
public class BaseClass
{
public void DoSomething()
{
var property = GetProperty(new Person(), (property) => p.Name == "Name");
}
}
然后我从单元测试中调用此方法。
var person = new Person();
person.DoSomething();
使用typeof(T)
时,会返回BaseClass
。如果我使用item.GetType()
则返回Person。如果我在调试器中检查它们,T
类型为BaseClass
,item
类型为Person
。当T
已经知道typeof(Person)
是个人时,为什么不推断item
是this
?
我的例子上面的错误很抱歉,当我致电GetProperty时,我通过了public class BaseClass
{
public void DoSomething()
{
var property = GetProperty(this, (property) => p.Name == "Name");
}
}
。
{{1}}
答案 0 :(得分:2)
这个推理问题的原因是通用推理在编译时发生,因此与手动指定所需类型相同。如果切换到使用调用显式声明<Person>
,它是否在编译期间抛出错误?
解决这个问题的一种方法是确保传入的变量(注意:不是对象!)明确属于Person
类,因为它似乎在您的代码中。另一种方法是通过使用dyanmic
对象强制在运行时进行泛型推理:
GetProperty(this as dynamic, (prop) => prop.Name == "Name");
通过投射this as dynamic
,它会在运行时使用GetProperty<dynamic>
的确切类型调用this
。这种方法的问题在于动态与其他对象相比非常慢。
如果模型严格来说是单个继承级别,您还可以使用静态多态来处理泛型参数。正是如此:
public class BaseClass<TSelf> where TSelf : BaseClass<TSelf>
public sealed class Model : BaseClass<Model>
通过这种方式,您可以使用TSelf
作为参数代替T
,这样就完全正确了。这种方法的问题在于它严格限制您使用扁平的单继承层次结构,因为从Model
继承的任何内容都会返回到原始问题并被视为Model
,因为它可以&#39; t覆盖其基类使用的泛型参数。
假设您的GetProperty函数执行了一些反射以检查属性,您可能需要考虑将Type
对象传入,而不是使用泛型,然后typeof(T)
,.GetType()
更加准确。