C# 是否可以将属性作为参数传递

C# 是否可以将属性作为参数传递,c#,C#,如果这听起来太不可能了,请不要投反对票:)这只是我的一个怪癖,我想知道我是否可以将一个属性作为参数传递给一个函数以得到一些结果 RemoveRows (DataGridView.Rows); //or RemoveRows (DataGridView.SelectedRows); 例如 void delete_button_click () { foreach (DataGridViewRow row in dgvRecords.SelectedRows) dgvRec

如果这听起来太不可能了,请不要投反对票:)这只是我的一个怪癖,我想知道我是否可以将一个属性作为参数传递给一个函数以得到一些结果

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

void delete_button_click ()
{
    foreach (DataGridViewRow row in dgvRecords.SelectedRows)
        dgvRecords.Rows.Remove(row);
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
假设

void delete_all_button click ()
{
    foreach (DataGridViewRow row in dgvRecords.Rows)
        dgvRecords.Rows.Remove(row);
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
我是否可以在一个函数中写入上述两个代码,因为唯一的区别是
SelectedRows
Rows
。大概是这样的:

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

{
   button_click(DataGridView.Rows);
   //and
   button_click(DataGridView.SelectedRows);
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
RemoveRows ((IEnumerable)dgvRecords.Rows);
//or
RemoveRows ((IEnumerable)dgvRecords.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;
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
decimal GetAmount1(用户usr)
{
十进制和=0;
foreach(dgvRecords.Rows中的DataGridViewRow行)
{
Tuple tup=(Tuple)row.Tag;
if(tup.Item1==usr)
sum+=tup.Item4.sum;
}
回报金额;
}

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
decimal GetAmount2(用户usr)
{
十进制和=0;
foreach(dgvRecords.Rows中的DataGridViewRow行)
{
Tuple tup=(Tuple)row.Tag;
if(tup.Item2==usr)
sum+=tup.Item4.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;
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
decimal GetAmount(用户usr,Tuple.Property项)
{
十进制和=0;
foreach(dgvRecords.Rows中的DataGridViewRow行)
{
Tuple tup=(Tuple)row.Tag;
如果(tup.Item==usr)
sum+=tup.Item4.sum;
}
回报金额;
}
并致电:

{ 
     GetAmount(usr, Tuple<User, User, Notification, Acknowledgment>.Item1)
     //and
     GetAmount(usr, Tuple<User, User, Notification, Acknowledgment>.Item2)   
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
{
GetAmount(usr,Tuple.Item1)
//及
GetAmount(usr,Tuple.Item2)
}

??

解决第一个问题并不需要投影,但为了便于选择属性,您可以传入投影以允许调用方选择属性,例如,在您的第一组方法中,您可以这样做

   void DeleteRows(DataGridView dgv, Func<DataGridView, IEnumerable> projection)
   {
        foreach (DataGridViewRow row in projection(dgv))
            dgv.Rows.Remove(row);
   }
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
也就是说,在任何情况下,如果要动态传入属性,请传入接受对象并返回所需属性的
Func
。这与LINQ通过允许调用者指定查询数据的投影来创建此类通用算法的方式非常相似

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
当然,如果您有接受委托的
public
方法,请确保在调用它们之前它们是非
null
。如果它们是您控制下的
私有
方法,那么如果您控制对它们的所有调用,问题就没有那么大了

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
更新例如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;
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);

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

因为元组很大,所以这个有点难看,但仍然有效

您的第一个示例是,只需使用法线参数即可解决:

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
删除行的方法的签名为:

void RemoveRows (IList rows)
{
    foreach (var row in rows)
        dgvRecords.Rows.Remove(row);
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
并称之为:

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
第二个示例需要使用,它允许您定义要选择的属性

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
因此,您的
GetAmount()
方法siganture变为:

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
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;
}

您可以通过反射来实现这一点,但我不推荐这样做。下面是获取属性“getter”并使用它的示例:

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
    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对象,这样您就不必每次都重新创建它。

这是@Alastair-Pitts方法,但我对代码做了一些更改以使其正常工作

RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
 void RemoveRows (IEnumerable rows)
 {
     foreach (DataGridViewRow row in rows)
         dgvRecords.Rows.Remove(row);
 }
叫它

{
   button_click(DataGridView.Rows);
   //and
   button_click(DataGridView.SelectedRows);
}
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);
RemoveRows ((IEnumerable)dgvRecords.Rows);
//or
RemoveRows ((IEnumerable)dgvRecords.SelectedRows);

正如阿拉斯泰尔所指出的那样,我试过使用IEnumerable,但它不起作用。不可能将非泛型转换为泛型。IEnumerable位于
System.Collections
命名空间中,而不是像IEnumerable一样位于
System.Collections.Generic
命名空间中。尽管如此,我还是把他的答案记下来。

太好了。。对于我问题中的第二个示例,类似的代码是什么?我觉得有点不一样谢谢。。让我把这个标记为答案,因为你首先给出了一个答案。这不起作用。我指的是第一个例子。原因是
DataGridViewRowCollection
DataGridViewSelectedRowCollection
是different@nawfal:您可以使用
IEnumerable
,然后,您所需要做的就是能够迭代集合,并且两者都实现
IEnumerable
,并且都包含
DataGridViewRow
。我会编辑答案。@nawfal:谢谢你的提醒,欢迎随时更正!极好的正是我想要的。我想我不应该为发布任何疯狂的问题感到羞耻,语言中可能仍然存在一个解决方案:)一点也不。我的建议是首先考虑最简单的事情,通常这是正确的方法:)nawfal:woops,这是因为
IEnumerable
没有
.Remove()
。似乎
IList
定义了
.Remove()
方法。我已经更新了答案。现在我该如何调用该方法?我试过这样做:
removows(dgvRecords.Rows)
,这会导致编译错误。我试过这样做:
removows((IList)dgvRecords.Rows)
但我在运行时出错,说这样的强制转换无效。@nwfal:hmm,sry。试试我的最新更新。IList似乎不是通用的。试着把它作为一个普通的
IList
,通过使用
var
关键字,我们并不真正关心
行的类型是什么。另外,您得到的编译错误是什么?可能是
RemoveRows (DataGridView.Rows);
//or
RemoveRows (DataGridView.SelectedRows);