2016-12-27 121 views
1

我在源格式和目標格式之間有m-to-n關聯。 (現在,m = 2和n = 5,n增長快於m)。用相同的參數實例化不同的數據類型

我希望得到一個事件,輸入格式是一個ItemDbDataReader,並將其轉換成其他類型的,應當提供必要的構造函數:

public MyEvent(Item item) 
public MyEvent(DbDataReader ddr) 

public MyEventDetailed(Item item) 
public MyEventDetailed(DbDataReader ddr) 

public MyEventInfo(Item item) 
public MyEventInfo(DbDataReader ddr) 

public MyEventNotification(Item item) 
public MyEventNotification(DbDataReader ddr) 

public MyEventReminder(Item item) 
public MyEventReminder(DbDataReader ddr) 

每個構造是由只有一個使用兩個數據存儲:

EwsDataStore : DataStoreBase 
DbDataStore : DataStoreBase 

其現在各自實現從DataStoreBase抽象getEvent方法:

abstract MyEventDetailed getEvent(string uniqueId); 

現在我需要的所有其他目標格式一樣,所以我要讓他們一般是這樣的:

abstract T getEvent<T>(string uniqueId) where T : IEvent, new() 

有可能EwsDataStore實現是

getEvent<T>(string uniqueId) where T : IEvent, new() // TODO: All affected models have to implement IEvent interface 
{ 
    Item item; 
    try { 
     item = Item.Bind(service, new ItemId(uniqueId)); 
    } catch(Exception e) { 
     throw new ArgumentException("An item by that Id was not found in the data store", "uniqueId", e); 
    } 
    // return T.FromItem(item); // Needs static IEvent.FromItem method. 
    return new T(item); // IEvent has to enforce constructor with parameter Item on all implementing classes 
} 

和SQL:

getEvent<T>(string uniqueId) where T:IEvent, new() // TODO: All affected models have to implement IEvent interface 
{ 
    SQL db = new SQL(); 
    db.AddParameter("@uniqueId", uniqueId) 
    SqlDataReader sdr = db.ExecuteReader("SELECT * FROM datastore WHERE uniqueId = @uniqueId"); 
    if(!sdr.HasRows) throw new ArgumentException("An item by that Id was not found in the data store"); 
    sdr.Read(); 
    // return T.FromDdr(sdr); // Needs static IEvent.FromDdr method. 
    return new T(sdr); // IEvent has to enforce constructor with parameter DataReader on all implementing classes 
} 

但既不是帶參數的構造函數,也不是靜態的方法將在一般類型被允許,每個拋以下兩個錯誤消息之一:

修飾語「靜態」是無效的這個項目
「T」:創建的實例時不能提供的參數變量類型

搜索這些錯誤消息;我發現"the instance method can simply (sic!) delegate to a static method",或者我可以使用ReflectionActivator

沒有一個看起來足夠簡單/直接地寫,理解,使用和維護。

是否有一種直接的方式使用繼承和泛型來創建基於我提供的類型的所有不同類型,即使它們在C#繼承中沒有精通深入,其他程序員可以理解/遵循這些類型嗎?

回答

1

首先,我想你是誤解了new約束。 new意味着泛型類型T有一個無參數的構造函數new T(),這似乎與您想要的相反。

只要簡單地除去new約束和使用Activator類中創建的T實例:Activator.CreateInstance

return (T)Activator.CreateInstance(typeof(T), item); 

另外,請注意,您不能在接口定義靜態成員,也可以繼承他們。因此,在語言中沒有辦法對通用類型T表達約束,這將允許您致電T.MyStaticMethod()

+0

這將意味着缺少構造函數會導致運行時錯誤,而不是編譯時錯誤。是否有可能導致編譯時錯誤? – Alexander

+0

@Alexander不,沒有辦法強制'T',以便它具有可訪問的構造函數,而不管簽名是什麼。 'new'只強制'new T()'是一個有效的調用。 – InBetween

相關問題