使用C#创建一个Lambda字典

5
我遇到了一个问题,无法定义一个用于快速访问Lambda表达式的字典。
假设我们有一个常见的类,如下所示:
class Example
{
    public string Thing1;
    public DateTime Thing2;
    public int Thing3;
}

英译中:

我想做的是类似这样的事情:

var getters = new Dictionary<string, IDontKnowWhatGoesHere>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);

这是否可能?
编辑:
这是我使用此对象的情况:
List<Example> array = new List<Example>();

// We actually get this variable set by the user
string sortField = "Thing2";

array.Sort(getters[sortField]);

非常感谢您的帮助。

你能说一下你需要这个的原因吗?那样我们可以写出更好的解决方案。 - nikodz
为什么要使用字典?为什么不使用 List<Example> 呢?这样你就可以在上面使用 LINQ。没有必要限制你可以保存的数据量。 - gunr2171
嗨,我想快速访问Lambda表达式。例如... IEnumerable <Example> a; a.OrderBy(getters [“Thing3”]) - Adrian Salazar
为什么不实现一个“Example”的扩展方法来创建所需的getter呢?(我假设你所说的“众所周知”是指某个库类,你无法编辑它以添加所需的getter。)或者如果只是通过名称获取属性,那么反射可能会有用。 - Denise Skidmore
@DeniseSkidmore 通过“知名类”,我指的是它不是匿名的。因此,它是在一个文件中定义的,我可以更改它。 - Adrian Salazar
显示剩余2条评论
4个回答

8
你有几个选择。如果,就像你的例子一样,你想要获取的所有东西都是同一类型(即String),你可以这样做:
var getters = new Dictionary<string, Func<Example, String>>();

但是,如果它们是不同的类型,你需要使用最低公共子类,大多数情况下将是 Object

var getters = new Dictionary<string, Func<Example, object>>();

请注意,然后您将需要将返回值转换为您期望的类型。

按键,是的。按值,不太行:委托不实现IComparable,因此您需要编写自己的IComparer。如果这是您的意图,您可能会发现使用表达式更容易,例如Dictionary<string,Expression<Func<Example,string>> - 但这是一个全新的问题。 - RoadieRich
对不起,你误解了我的意思,我想做的是这样的:List<Example> a; a.OrderBy(getters["Thing1"]); 我需要解决的问题是在不写超级大的switch case的情况下实现动态的OrderBy。排序字段来自客户端。 - Adrian Salazar
@AdrianSalazar 我没有注意到你的编辑。在这种情况下,即使使用 Func<Example, object>,它也可以正常工作。 - RoadieRich
谢谢,我已经实现了它并且它运行良好。轻量级动态排序,无需使用反射... - Adrian Salazar

3

尝试:

var getters = new Dictionary<string, Func<Example, object>>();
getters.Add("Thing1", x => x.Thing1);
getters.Add("Thing3", x => x.Thing3);

Func委托的第一个通用类型参数是输入的类型,第二个通用类型参数是输出的类型(使用object是因为有不同的输出类型)。 更多关于Func的信息: Func<T, TResult> 委托


3
var getters = new Dictionary<string, Expression<Func<Example, object>>>();

然而,string Thing1 应该是公开的。

在这种情况下,这个会有效吗?IEnumerable<Example>.OrderBy(getters["Thing1"]) - Adrian Salazar

1
我认为您的思路有误,为什么要使用字典呢?如果您的类定义正确,只需使用List<Example>即可。
List<Example> dataList = new List<Example>();
dataList.Add(new Example { Thing1 = "asdf", Thing2 = "qwert", Thing3 = 2 });

然后你可以在其中使用LINQ。
IEnumerable<Example> sortedByT3 = dataList.OrderBy(x => x.Thing3);

sortedByT3.Last().Thing2 = "hjkl";

你可以使用Marc Gravell的回答提供的动态排序
var sortedByString = dataList.AsQueryable().OrderBy("Thing2");

无需使用lambda表达式,直接访问数据即可。

正如其他人所说,您需要将成员变量设置为公共的。我建议您将其更改为以下内容:

public class Example
{
    public string Thing1 { get; set; }
    public string Thing2 { get; set; }
    public int Thing3 { get; set; }
}

是的,我明白你的意思,问题在于我需要知道第一次要按哪个字段进行排序。所以我可以像我们古老的程序员一样做一个大的switch case。我可以接受这种方式,但我想知道DLR、TypeInference、Generics和Lambdas是否可以给我另一种方法。 - Adrian Salazar
@AdrianSalazar,类似于“动态LINQ”这样的东西?http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx - gunr2171
是的,你理解了我的意思,但我根本没有连接到SQL...而且我不想在一天内拯救世界并使其超级通用。如果它与这个特定的类一起工作,那就足够了。 - Adrian Salazar
@AdrianSalazar,好的,我明白你的意思了。我再给你一个建议:https://dev59.com/nnVD5IYBdhLWcg3wQJKT,并且我会保留这个答案以备将来参考。 - gunr2171

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接