2011-12-19 59 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 <>。不过,我正在把他当作答案。

相关问题