2011-12-19 62 views
2

如果這聽起來太不可能了,請不要投票:)只是我的怪癖,我想知道如果我可以傳遞一個屬性作爲參數傳遞給函數來獲得一些結果。是否有可能通過屬性作爲參數

例如,

void delete_button_click() 
{ 
    foreach (DataGridViewRow row in dgvRecords.SelectedRows) 
     dgvRecords.Rows.Remove(row); 
} 

並假設

void delete_all_button click() 
{ 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
     dgvRecords.Rows.Remove(row); 
} 

我可以寫上面的兩個代碼在一個函數,因爲唯一的區別是SelectedRowsRows。事情是這樣的:

void button_click (/*DataGridView property rows*/) 
{ 
    foreach (DataGridViewRow row in dgvRecords.rows) 
     dgvRecords.Rows.Remove(row); 
} 

,並調用它

{ 
    button_click(DataGridView.Rows); 
    //and 
    button_click(DataGridView.SelectedRows); 
} 

另如,

decimal GetAmount1(User usr) 
{ 
    decimal sum = 0; 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
    { 
     Tuple<User, User, Notification, Acknowledgment> tup = (Tuple<User, User, Notification, Acknowledgment>)row.Tag; 
     if (tup.Item1 == usr) 
      sum += tup.Item4.Sum; 

    } 
    return sum; 
} 

decimal GetAmount2(User usr) 
{ 
    decimal sum = 0; 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
    { 
     Tuple<User, User, Notification, Acknowledgment> tup = (Tuple<User, User, Notification, Acknowledgment>)row.Tag; 
     if (tup.Item2 == usr) 
      sum += tup.Item4.Sum; 

    } 
    return sum; 
} 

在上面的代碼唯一的區別只是一個屬性。因此,這是可供選擇:

decimal GetAmount(User usr, Tuple<User, User, Notification, Acknowledgment>.Property Item) 
{ 
    decimal sum = 0; 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
    { 
     Tuple<User, User, Notification, Acknowledgment> tup = (Tuple<User, User, Notification, Acknowledgment>)row.Tag; 
     if (tup.Item == usr) 
      sum += tup.Item4.Sum; 

    } 
    return sum; 
} 

而且撥打:

{ 
    GetAmount(usr, Tuple<User, User, Notification, Acknowledgment>.Item1) 
    //and 
    GetAmount(usr, Tuple<User, User, Notification, Acknowledgment>.Item2) 
} 

+0

可能重複的[如何傳遞一個類的屬性作爲方法的參數?](http://stackoverflow.com/questions/1178574/how-can-i-pass-a-property-of -a-class-as-a-parameter-of-method) – nawfal

回答

3

你的第一個例子可以只使用一個正常的參數來解決:

的方法來刪除行的簽名是:

void RemoveRows (IList rows) 
{ 
    foreach (var row in rows) 
     dgvRecords.Rows.Remove(row); 
} 

,並稱之爲:

RemoveRows (DataGridView.Rows); 
//or 
RemoveRows (DataGridView.SelectedRows); 

第二個示例需要使用Func<T, TResult>,它允許您定義要選擇的屬性。

所以你GetAmount()方法siganture變爲:

decimal GetAmount(User usr, Func<Tuple<User, User, Notification, Acknowledgment>, User> selector) 
{ 
    decimal sum = 0; 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
    { 
     Tuple<User, User, Notification, Acknowledgment> tup = (Tuple<User, User, Notification, Acknowledgment>)row.Tag; 
     if (selector(tup) == usr) 
      sum += tup.Item4.Sum; 

    } 
    return sum; 
} 

,你會稱它爲:

GetAmount(usr, tuple => tuple.Item1); 
//or 
GetAmount(usr, tuple => tuple.Item1); 
+0

太棒了!正是我想要的。我認爲我不應該爲發佈任何瘋狂的問題感到羞恥,解決方案可能仍然存在於該語言中:) – nawfal

+1

根本不是。我的建議是首先想到最簡單的東西,通常這是正確的方式去:) –

+0

是:)............ – nawfal

1

您並不需要投影來解決第一個問題,但爲了選擇屬性的參數,您可以傳入投影以允許調用者選擇屬性,例如在您的第一組方法,你可以做。

void DeleteRows(DataGridView dgv, Func<DataGridView, IEnumerable> projection) 
    { 
     foreach (DataGridViewRow row in projection(dgv)) 
      dgv.Rows.Remove(row); 
    } 

,或者使用泛型:

void DeleteRows<TCollection>(DataGridView dgv, Func<DataGridView, TCollection> projection) where TCollection : IEnumerable 
    { 
     foreach (DataGridViewRow row in projection(dgv)) 
      dgv.Rows.Remove(row); 
    } 

然後,你可以這樣調用它:

// delete all rows 
    DeleteRows(dgvRecords, d => d.Rows); 

    // delete only selected rows 
    DeleteRows(dgvRecords, d => d.SelectedRows); 

也就是說,當你想在一個屬性將動態任何情況下,而是傳入一個Func<...>,它接受該對象並返回所需的屬性。 LINQ通過允許調用者指定查詢數據的投影來創建這樣的通用算法,這非常相似。

當然,如果您有public方法採取代表,請確保它們在調用它們之前不是null。如果他們的方法在你的控制之下,那麼如果你控制了對它們的所有呼叫,那麼它就不是什麼大問題。

UPDATE例如2:

decimal GetAmount(User usr, Func<Tuple<User, User, Notification, Acknowledgement>, User> projection) 
{ 
    decimal sum = 0; 
    foreach (DataGridViewRow row in dgvRecords.Rows) 
    { 
     Tuple<User, User, Notification, Acknowledgment> tup = (Tuple<User, User, Notification, Acknowledgment>)row.Tag; 
     if (projection(tup) == usr) 
      sum += tup.Item4.Sum; 

    } 
    return sum; 
} 

而且撥打:

GetAmount(user, t => t.Item1); 

或者

GetAmount(user, t => t.Item2); 

這一個有點難看,因爲大Tuple的,但仍然有效。

+0

太好了..在我的問題中,第二個例子的代碼類似嗎?我發現它有點不同 – nawfal

+0

謝謝..讓我把這個標記爲答案,因爲你首先提出了一個答案。 – nawfal

+0

這不起作用。我的意思是第一個例子。原因是'DataGridViewRowCollection'和'DataGridViewSelectedRowCollection'是不同的 – nawfal

1

你可以用反射做到這一點,但我不會推薦它。這裏是得到一個屬性「getter」和與它一起工作的一個例子:

int someFunction(Element instance, string propertyName) 
    { 
     MethodInfo prop = typeof(Element).GetProperty(propertyName).GetGetMethod(); 
     if (prop.ReturnType != typeof(int)) 
     { 
      throw new Exception("Type of property does not match expected type of int"); 
     } 
     return (int)prop.Invoke(instance, null); 
    } 

同樣,我不建議做這樣的事,除非你有比上面提到的一個更好的理由。如果你這樣做,你應該儘量緩存MethodInfo對象,所以你不需要每次都重新創建它。

0

這是@Alastair Pitts方法,但我稍微更改一下代碼以使其工作。

void RemoveRows (IEnumerable rows) 
{ 
    foreach (DataGridViewRow row in rows) 
     dgvRecords.Rows.Remove(row); 
} 

,並調用它

RemoveRows ((IEnumerable)dgvRecords.Rows); 
//or 
RemoveRows ((IEnumerable)dgvRecords.SelectedRows); 

我曾與IEnumerable的<>由阿拉斯泰爾指出的,但它wouldnt工作的審判。無法將非泛型轉換爲泛型。 IEnumerable位於命名空間System.Collections中,不位於System.Collections.Generic命名空間中,如IEnumerable <>。不過,我正在把他當作答案。

相關問題