2009-12-14 72 views
2

这个问题的主要问题是,当我们将T传递给某个函数并使用它来像下面的语句一样投射一些对象时。如何将一些对象转换为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

你说有问题发生,但你没有说出什么问题。如果你传入UserInfo for T,那么你期望发生什么?你还没有为UserInfo定义一个验证器,所以这应该返回null。不是吗?有什么问题? – 2009-12-14 15:43:42

+0

我认为这个问题与协变有关 - 'GetCustomAttribute'为'UserInfo'返回一个'IValidator '实例,因为**基类**被标记了该属性。因此,'GetValidator '会抛出'InvalidCastException',因为泛型类型参数不一样。 – Groo 2009-12-14 16:10:31

+0

我明白你的观点。在这种情况下,你会想*反变换*,而不是*协变*。 – 2009-12-14 16:26:34

回答

2

我还没有安装.NET 4.0,所以我不确定如何正确使用协方差,但即使在.Net 2.0和3.5中,您也可以使用Duck Typing库获得协变支持。duck typing library by David MeyerLinFu by Philip Laureano

换句话说,在GetValidator<T>最后一行应该是这样的:

// http://www.deftflux.net/blog/page/Duck-Typing-Project.aspx 
return DuckTyping.Cast<IValidator<T>> 
    Activator.CreateInstance(attribute.ValidatorType); 

或(使用李林甫)

// 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:

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 should handle covariance,但我没有测试它。这个例子可以在任何.Net版本中使用,所以我将其包含在内。

+0

我想你想念我的问题。我的问题的主要问题是如何创建T的父对象的新对象。请阅读我更新的问题#1。 – 2009-12-14 14:44:19

+0

我认为你的更新答案对于解决问题和被接受的答案是非常明确的。顺便说一句,在我真正的问题中,我用另一种方式解决了这个问题,这个问题的复杂性比这个答案要小。 – 2009-12-15 01:38:29

2

我假设你正在寻找的协方差,但该功能(新的C#4)仅适用于接口,而不是类。

编辑:根据你的编辑,你的意思是co-/contravariance。但是,如果界面IValidator<T>可以变为协变(这似乎是您正在寻找的内容),则取决于界面的方法和属性。

0

这听起来像你需要约束T的类型,你创造一些接口:

void SomeFunction<T> (object model) where T : IHasParent 
{ 
    var parent = ((T)model).GetParent(); 
} 

public interface IHasParent 
{ 
    object GetParent(); 
} 

这就是所谓的generic constraint

我猜你应该能够做到这一点太:

void SomeFunction<T> (T model) where T : IHasParent 
{ 
    var parent = model.GetParent(); 
} 

public interface IHasParent 
{ 
    IHasParent GetParent(); 
} 

我希望这给你一些想法向前走,让我们知道你的作品。

您可以通过多种方式处理空值,我将其作为练习留给您。例如,搜索Null Coalescing Operator

+0

这不是我的观点。请阅读我更新的问题。 – 2009-12-14 09:58:20

+0

我相信OP并不完全是指“父类”,而是继承层次结构中的“基类”。 – Groo 2009-12-14 16:12:19

相关问题