3
\$\begingroup\$

I have the following code (I need the LambdaExpression as not all Func<>'s are T, int):

var orderDelegates = new Dictionary<string, LambdaExpression>();
Expression<Func<Image, int>> id = i => i.Id;
orderDelegates.Add(ContentItem.ORDER_BY_ID, id);

Is it possible to make this shorter?

Best something like:

var orderDelegates = new Dictionary<string, LambdaExpression>()
{
 { ContentItem.ORDER_BY_ID, ????? },
 ...
};

I already tried the following, which did not work:

orderDelegates.Add(ContentItem.ORDER_BY_ID, (Expression<Func<Image, int>>)i => i.id);
//or
orderDelegates.Add(ContentItem.ORDER_BY_ID, i => i.id as Expression<Func<Image, int>>);

I "improved" it a little to the following already, but "full inlining" would be the desired result:

public static Dictionary<string, LambdaExpression> GetOrderDelegates<T>() where T : ContentItem
{
 Expression<Func<T, int>> id = i => i.Id;
 Expression<Func<T, bool>> enabled = i => i.IsEnabled;
 Expression<Func<T, IComparable>> author = i => i.Creator.UserName;
 //...
 return new Dictionary<string, LambdaExpression>()
 {
 { ContentItem.ORDER_BY_ID, id },
 { ContentItem.ORDER_BY_ENABLED, enabled },
 { ContentItem.ORDER_BY_AUTHOR, author },
 //...
 };
}
Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Aug 17, 2013 at 8:26
\$\endgroup\$
4
  • \$\begingroup\$ So, what do you know about the lambdas, are they all Func<Image, something> or at least Func<something1, something2>? \$\endgroup\$ Commented Aug 17, 2013 at 11:16
  • \$\begingroup\$ @svick: Yes, they are all Func<T, something>... \$\endgroup\$ Commented Aug 17, 2013 at 11:45
  • \$\begingroup\$ whats ContentItem? \$\endgroup\$ Commented Aug 17, 2013 at 12:38
  • \$\begingroup\$ @Nik: ContentItem is my base class, which holds all common properties like Id and all my (content-)items use classes derived from it ... \$\endgroup\$ Commented Aug 17, 2013 at 17:25

1 Answer 1

1
\$\begingroup\$

You can do this by creating a custom class that supports collection initializers. Its Add() method would be generic, so that it fits any allowed expression:

class ExpressionDictionary<T> : IEnumerable<KeyValuePair<string, LambdaExpression>>
{
 private readonly Dictionary<string, LambdaExpression> m_dictionary
 = new Dictionary<string, LambdaExpression>();
 public void Add<TResult>(string key, Expression<Func<T, TResult>> expression)
 {
 m_dictionary.Add(key, expression);
 }
 public IEnumerator<KeyValuePair<string, LambdaExpression>> GetEnumerator()
 {
 return m_dictionary.GetEnumerator();
 }
 IEnumerator IEnumerable.GetEnumerator()
 {
 return GetEnumerator();
 }
}

Usage:

new ExpressionDictionary<T>
{
 { ContentItem.ORDER_BY_ID, i => i.Id },
 { ContentItem.ORDER_BY_ENABLED, i => i.IsEnabled },
 //the cast is necessary if the result has to be Func<T, IComparable>
 // and not Func<T, string>
 { ContentItem.ORDER_BY_AUTHOR, i => (IComparable)i.Creator.UserName },
 //...
};

You will need to add other methods to ExpressionDictionary. Either implement the whole IDictionary<TKey, TValue> interface and make GetOrderDelegates() return that. Or just add a getter for the private Dictionary and return that.

But even better option might be not to use Dictionary at all. Instead create OrderByDeletegates class (though that's probably not the best name, since it would contain expressions, not delegates) that would have properties for all expressions:

class OrderByDeletegates<T> where T : ContentItem
{
 public Expression<Func<T, int>> OrderById { get; set; }
 public Expression<Func<T, bool>> OrderByEnabled { get; set; }
 public Expression<Func<T, IComparable>> OrderByAuthor { get; set; }
 // ...
}

Usage:

new OrderByDeletegates<T>
{
 OrderById = i => i.Id,
 OrderByEnabled = i => i.IsEnabled,
 OrderByAuthor = i => i.Creator.UserName,
 // ...
};

The advantage of this is that it's type-safe. You can't for example accidentally do something like OrderByEnabled = i => i.Id.

answered Aug 17, 2013 at 12:50
\$\endgroup\$
5
  • \$\begingroup\$ This are great ideas, but the second one will not work in my case, as I use the string-key of the dictionary to select the correct delegate/expression... I try implementing your first idea as an extension to my dictionary and report back. \$\endgroup\$ Commented Aug 17, 2013 at 17:30
  • \$\begingroup\$ @chrfin Why do you need to use the key? Can't you just access the properties directly? \$\endgroup\$ Commented Aug 17, 2013 at 18:19
  • \$\begingroup\$ Because the key comes in as a string from the (Web-)Front-End (e.g "mydomain.com/page?sortKey=Author" will sort after the expression with the key "Author")... \$\endgroup\$ Commented Aug 17, 2013 at 19:20
  • \$\begingroup\$ Went with your first solution and works fine... \$\endgroup\$ Commented Aug 18, 2013 at 9:16
  • \$\begingroup\$ note that Expression<Func<T, TResult>> does not guarantee that TResult is a member of T which I think was the op intent \$\endgroup\$ Commented Jun 17, 2021 at 0:13

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.