5

I'm having a trouble defining a Dictionary for quick accessing Lambda Expressions.

Let's suppose we have a well-known class like this:

class Example
{
    public string Thing1;
    public DateTime Thing2;
    public int Thing3;
}

What a want to do is something like this:

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

Is this possible?

Edit:

This is my use case for this object:

List<Example> array = new List<Example>();

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

array.Sort(getters[sortField]);

Many thanks for your help.

Adrian Salazar
  • 5,279
  • 34
  • 51
  • You are trying to store a `Func` as the value type in the dictionary? Is this what you want? What are you trying to use this for? – gunr2171 Jul 30 '13 at 13:31
  • so you want to store expressions? – ne2dmar Jul 30 '13 at 13:32
  • Can you say what for you need this? Then we will write better solution. – nikodz Jul 30 '13 at 13:34
  • Why use a dictionary at all? Why not have a `List`? Then you can use linq on that. No need to limit the amount of data you can hold. – gunr2171 Jul 30 '13 at 13:36
  • Hey, I want to have a quick access to the lambda expressions. For example... IEnumerable a; a.OrderBy(getters["Thing3"]) – Adrian Salazar Jul 30 '13 at 13:37
  • Why not implement an extension method of 'Example' to create the getters you want? (I assume by "well-known" you mean some library class you can't edit yourself to add the getter you want.) Or if it's really just grabbing properties by name, reflection might be useful. – Denise Skidmore Jul 30 '13 at 13:43
  • @DeniseSkidmore By well-known class I mean, it is not anonymous. So it is defined in a file which I can change. – Adrian Salazar Jul 30 '13 at 13:44

4 Answers4

8

You've got a couple of options. If, as in your example, the things you want to get are all the same type (i.e. String), you can do

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

However, if they're different types, you'll need to use the lowest common subclass, which in most cases will be Object:

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

Note that you'll then need to cast the return value into your expected type.

RoadieRich
  • 6,330
  • 3
  • 35
  • 52
  • By key, yes. By Value, not really: delegates do not implement `IComparable`, so you'll need to write your own `IComparer`. If that's your intention, you might find it easier to use expressions, as in `Dictionary>` - but that's a whole new problem. – RoadieRich Jul 30 '13 at 13:56
  • I'm sorry you got me wrong, I want to do this: List a; a.OrderBy(getters["Thing1"]); The problem that I need to solve is to make dynamic OrderBy without writing the mega massive switch case. The Sort field is coming from client-side – Adrian Salazar Jul 30 '13 at 14:03
  • @AdrianSalazar I hadn't noticed your edit. It will work fine in that case, even with `Func`. – RoadieRich Jul 30 '13 at 14:05
  • Thanks I have implemented it and it works. Lightweight dynamic sort without using reflection... – Adrian Salazar Jul 30 '13 at 14:49
3

Try:

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

The first generic type parameter of the Func delegate is the type of the input, and the second generic type parameter is the type of the output (use object because you've different output types). More about Func: Func<T, TResult> Delegate

ProgramFOX
  • 6,131
  • 11
  • 45
  • 51
3
var getters = new Dictionary<string, Expression<Func<Example, object>>>();

However, string Thing1 should be public.

empi
  • 15,755
  • 8
  • 62
  • 78
1

I really think you are thinking about this in the wrong way. Why use a dictionary at all? If your class definition is correct, then just use a List<Example>.

List<Example> dataList = new List<Example>();
dataList.Add(new Example { Thing1 = "asdf", Thing2 = "qwert", Thing3 = 2 });

Then you can use linq on it.

IEnumerable<Example> sortedByT3 = dataList.OrderBy(x => x.Thing3);

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

You can also use a dynamic order by provided by Marc Gravell's answer:

var sortedByString = dataList.AsQueryable().OrderBy("Thing2");

No need for lambdas, just direct access to the data.

As everyone has said, you need to make the members public. I would suggest you change it to the following:

public class Example
{
    public string Thing1 { get; set; }
    public string Thing2 { get; set; }
    public int Thing3 { get; set; }
}
Community
  • 1
  • 1
gunr2171
  • 16,104
  • 25
  • 61
  • 88
  • Yes I get your point, the thing is that I need to know on which field I want to sort on the first time. So I can make a big switch case like our ancient programmers normally did. I can live with that, but I would like to know if DLR, TypeInference, Generics and Lambdas can give me another way of doing it. – Adrian Salazar Jul 30 '13 at 13:47
  • @AdrianSalazar, so something like `dynamic linq`? http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx – gunr2171 Jul 30 '13 at 13:48
  • Yes you got my point, but I'm not connected to SQL at all... and I don't want to save the world in one day and make it mega-generic. If it works with this particular class, then it's enough. – Adrian Salazar Jul 30 '13 at 13:50
  • @AdrianSalazar, ok, I see what you mean. I will leave you will one more suggestion: http://stackoverflow.com/q/41244/1043380 , and I will keep this answer up for future reference. – gunr2171 Jul 30 '13 at 13:57