这个问题的主要问题是当我们将T传递给某个函数并使用它来构建一些对象时,如下面的语句。
void SomeFunction<T> (object model)
{
(SomeClass<T>)model;
}
一切正常。但我想将模型对象转换为通用类对象,它是T的父级或T的祖父级,取决于非空的。怎么做?
更新了#1
如需更多了解,请查看以下示例。
public partial class SimpleUserInfo
{
public string LogOnName { get;set; }
public string HashedPassword { get;set; }
}
public partial class UserInfo : SimpleUserInfo
{
pubic string Address { get;set; }
}
创建一些数据模型后。我创建了一个使用UserInfo类作为参数的泛型类。
public class SimpleUserInfoValidator : IValidator<SimpleUserInfo>
{
// logic to validate simple user info instance
}
然后,我将属性添加到SimpleUserInfo类。
[Validator(typeof(SimpleUserInfoValidator))]
public partial class SimpleUserInfo {}
最后,我创建了一些函数来检索给定类T中的验证器。
public GetValidator<T> ()
{
var attribute = (ValidatorAttribute)Attribute.GetCustomAttribute(type, typeof(ValidatorAttribute));
if (attribute == null || attribute.ValidatorType == null)
return null;
var (IValidator<T>)Activator.CreateInstance(attribute.ValidatorType);
}
当T为SimpleUserInfo时,此函数将正常工作,但当T为UserInfo时会出现问题。怎么解决这个问题?
PS。要解决此问题,不需要使用C#4.0的新功能。但我只是告诉你我将在C#4.0中应用这个解决方案。
谢谢,
答案 0 :(得分:2)
我假设您正在寻找协方差,但该功能(C#4的新功能)仅适用于接口,而不适用于类。
编辑:根据您的编辑,您的意思是共同/逆转。但是,是否以及如何使接口IValidator<T>
变为协变(这似乎是您正在寻找的内容)取决于IValidator<T>
接口的方法和属性。
答案 1 :(得分:2)
我还没有安装.NET 4.0,所以我不确定正确使用协方差,但即使在使用Duck Typing库的.Net 2.0和3.5中也可以获得协方差支持(例如{{3} }或duck typing library by David Meyer:
换句话说,GetValidator<T>
中的最后一行应如下所示:
// http://www.deftflux.net/blog/page/Duck-Typing-Project.aspx
return DuckTyping.Cast<IValidator<T>>
Activator.CreateInstance(attribute.ValidatorType);
或(使用LinFu)
// http://www.codeproject.com/KB/cs/LinFuPart2.aspx
DynamicObject dynamicObj = new DynamicObject
(Activator.CreateInstance(attribute.ValidatorType));
return dynamicObj.CreateDuck<IValidator<T>>()
<强> [编辑] 强>
我可能没有理解你的问题,但我相信它归结为:
您有一个通用接口,其通用参数类型为T:
IValidator<SimpleUserInfo> simpleUserValidator;
您希望将其转换为相同的通用接口,但使用通用参数,该参数是T的 base 类:
IValidator<SimpleUserInfo> ---> IValidator<UserInfo>
简单转换不起作用,因为不支持泛型类型协方差(至少在旧版本的.Net中不支持):
// this will throw an invalid cast exception
IValidator<UserInfo> userValidator = (IValidator<UserInfo>) simpleUserValidator;
但它可以使用鸭子打字:
IValidator<UserInfo> userValidator =
DuckTyping.Cast<IValidator<UserInfo>> (simpleUserValidator);
再一次,.Net 4.0 LinFu by Philip Laureano,但我还没有测试过它。这个例子适用于任何.Net版本,所以我把它包括在内是为了完整起见。
答案 2 :(得分:0)
听起来你需要将T的类型约束到你创建的某个接口:
void SomeFunction<T> (object model) where T : IHasParent
{
var parent = ((T)model).GetParent();
}
public interface IHasParent
{
object GetParent();
}
我猜你也应该能够做到这一点:
void SomeFunction<T> (T model) where T : IHasParent
{
var parent = model.GetParent();
}
public interface IHasParent
{
IHasParent GetParent();
}
我希望这会给你一些前进的想法,让我们知道什么对你有用。
您可以通过多种方式处理空值,我会将其作为练习留给您。例如,搜索Null Coalescing Operator。