2009-12-14 47 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

相關問題