2009-11-22 97 views
0

下面我有這個重複的代碼,我假定這是可以合併,但如果你注意到各詞典是不同的通用字典:如何讓這個重複的代碼更優雅?

dictionary1的類型是

Dictionary<int, ContinuousIntegrationSolution> 

而dictionary2的類型爲:

Dictionary<int, BugTracker> 

     DataTable dt = GetDataTable("CI"); 
     for (int i = 0; i < dt.Rows.Count; i++) 
     { 
      DataRow dr = dt.Rows[i]; 
      int id = Convert.ToInt32(dr["id"]); 
      string name = dr["name"].ToString(); 
      _dictionary1[id] = new ContinuousIntegrationSolution(){Name = name}; 
     } 

     DataTable dt1 = GetDataTable("Bug_Tracking"); 

     for (int i = 0; i < dt1.Rows.Count; i++) 
     { 
      DataRow dr = dt1.Rows[i]; 
      int id = Convert.ToInt32(dr["id"]); 
      string name = dr["name"].ToString(); 
      _dictionary2[id] = new BugTracker() { Name = name }; 
     } 

     DataTable dt2 = GetDataTable("SDLC"); 

     for (int i = 0; i < dt2.Rows.Count; i++) 
     { 
      DataRow dr = dt2.Rows[i]; 
      int id = Convert.ToInt32(dr["id"]); 
      string name = dr["name"].ToString(); 
      _dictionary3[id] = new SDLCProcess() { Name = name }; 
     } 

注:我有固定的是下面提及的幾個錯別字。

+0

在你的代碼中有bug嗎?你有3個數據表(dt,dt1和dt2),但只有2個字典_dictionary1和_dictionary2? – 2009-11-22 19:24:02

+0

我們是否允許更改類級別,以便ContinuousIntegrationSolution,BugTracker和SDLCProcess具有包含名稱成員的公共基類或接口? – 2009-11-22 19:28:34

+0

另外dt沒有在代碼片段的範圍內定義。 – 2009-11-22 19:31:07

回答

13
public interface INameable 
{ 
    string Name {get;set;} 
} 

public static IDictionary<int, T> ReadTable<T>(string tableName) 
    where T : INameable, new() 
{ 
    DataTable dt = GetDataTable(tableName); 
    var dictionary = new Dictionary<int, T>(); 

    for (int i = 0; i < dt.Rows.Count; i++) 
    { 
     DataRow dr = dt.Rows[i]; 
     int id = Convert.ToInt32(dr["id"]); 
     string name = dr["name"].ToString(); 
     dictionary[id] = new T() { Name = name }; 
    } 
    return dictionary; 
} 

如果你有C#4.0的動態可以避開INameable的類型安全的一些(小)損失

的替代,在靜脈哈孔伯爵的答案,但沒有使詞典相仿的

public IDictionary<int,T> ReadTable<T>(
    string tableName, Action<T, string> onName) 
    where T : new() 
{ 
    var dictionary = new Dictionary<int,T>(); 
    DataTable table = GetDataTable(tableName); 
    foreach (DataRow row in table.Rows) 
    { 
     int id = Convert.ToInt32(row["id"]); 
     string name = row["name"].ToString(); 
     var t = new T(); 
     onName(t, name); 
     dictionary[id] = t; 
    } 
    return dictionary; 
} 

然後將其消耗像這樣:

var ci = ReadTable<ContinuousIntegrationSolution>("CI", 
       (t, name) => t.Name = name); 
var bt = ReadTable<BugTracker >("Bug_Tracking", 
       (t, name) => t.Name = name); 
var sdlc = ReadTable<SDLCProcess>("SDLC", 
       (t, name) => t.Name = name); 

的替代,更靈活approac小時,但還是相當簡單的,由於通話網站使用類型推斷是:

public IDictionary<int,T> ReadTable<T>(string tableName, Func<string,T> create) 
{ 
    DataTable table = GetDataTable(tableName); 
    var dictionary = new Dictionary<int,T>() 
    foreach (DataRow row in table.Rows) 
    { 
     int id = Convert.ToInt32(row["id"]); 
     string name = row["name"].ToString(); 
     dictionary[id] = create(name); 
    } 
    return dictionary; 
} 

,然後將其消耗掉,像這樣:

var ci = ReadTable("CI", 
       name => new ContinuousIntegrationSolution() {Name = name}); 
var bt = ReadTable("Bug_Tracking", 
       name => new BugTracker() {Name = name}); 
var sdlc = ReadTable("SDLC", 
       name => new SDLCProcess() {Name = name}); 

如果你去與拉姆達的方法,我會建議後者。

+0

它可以通過使用foreach進一步改進。 – 2009-11-22 19:34:46

+2

我同意,但這會改變提供的程序的語義(我承認這是一個微妙的變化),所以我傾向於在沒有必要時糾正這些問題。 – ShuggyCoUk 2009-11-22 19:36:43

+0

我收到此錯誤代碼並說:錯誤非泛型聲明不允許使用約束條件 – leora 2009-11-22 19:48:28

0

把它放在一個帶有工廠方法的函數中來實例化id對象。事情是這樣的......

public delegate T CreateObjectDelegate<T>(string name); 
public static void ProcessDataTable<T>(DataTable dt, Dictionary<int, T> dictionary, CreateObjectDelegate<T> createObj) 
{ 
    for (int i = 0; i < dt.Rows.Count; i++) 
    { 
     DataRow dr = dt.Rows[i]; 
     int id = Convert.ToInt32(dr["id"]); 
     string name = dr["name"].ToString(); 
     dictionary[id] = createObj(name); 
    } 
} 

static void Main(string[] args) 
{ 
    var dt = new DataTable(); 
    var dictionary = new Dictionary<int, BugTracker>(); 
    ProcessDataTable<BugTracker>(dt, dictionary, (name) => { return new BugTracker() { Name = name }; }); 
} 
3

我不會用一個接口就像有人提出,而是使用lambda函數做類似這樣的分配:

public void ReadTable(string tableName, Action<int, string> _setNameAction) { 
    DataTable table = GetDataTable(tableName); 
    foreach (DataRow row in table.Rows) { 
     int id = Convert.ToInt32(row["id"]); 
     string name = row["name"].ToString(); 
     _setNameAction(id, name); 
    } 
} 

並調用類的方法這個:

ReadTable("CI", (id, name) 
    => _dictionary1[id] = new ContinuousIntegrationSolution{Name = name}); 
ReadTable("Bug_Tracking", (id, name) 
    => _dictionary2[id] = new BugTracker { Name = name }); 
ReadTable("SDLC", (id, name) 
    => _dictionary3[id] = new SDLCProcess { Name = name }); 
+0

此代碼不起作用。 「id」在哪裏被傳回到Action委託? – leora 2009-11-22 19:52:50

+0

我剛剛想出了幾秒鐘之前,現在已經更新了 – HakonB 2009-11-22 19:54:53