如果这听起来太不可能了,请不要投票:)只是我的怪癖,我想知道我是否可以将属性作为参数传递给函数以获得一些结果。
例如。
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);
}
我可以在一个函数中编写上述两个代码,因为唯一的区别是SelectedRows
和Rows
。像这样:
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 :(得分: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);
答案 1 :(得分: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
。如果它们是您控制的private
种方法,那么如果您控制所有对它们的调用,则不会出现大问题。
更新例如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
,但是仍然有效,这个有点丑陋。
答案 2 :(得分: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对象,这样你就不需要每次都重新创建它。
答案 3 :(得分: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&lt;&gt;正如阿拉斯泰尔所指出的那样,它无济于事。将非泛型转换为泛型是不可能的。 IEnumerable位于System.Collections
名称空间中,而不是像{IE1}}名称空间中那样的IEnumerable&lt;&gt;。尽管如此,我还是将其作为答案。