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 },
//...
};
}
1 Answer 1
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
.
-
\$\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\$Christoph Fink– Christoph Fink2013年08月17日 17:30:00 +00:00Commented 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\$svick– svick2013年08月17日 18:19:39 +00:00Commented 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\$Christoph Fink– Christoph Fink2013年08月17日 19:20:20 +00:00Commented Aug 17, 2013 at 19:20
-
\$\begingroup\$ Went with your first solution and works fine... \$\endgroup\$Christoph Fink– Christoph Fink2013年08月18日 09:16:41 +00:00Commented 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\$kofifus– kofifus2021年06月17日 00:13:46 +00:00Commented Jun 17, 2021 at 0:13
Func<Image, something>
or at leastFunc<something1, something2>
? \$\endgroup\$Func<T, something>
... \$\endgroup\$ContentItem
? \$\endgroup\$ContentItem
is my base class, which holds all common properties likeId
and all my (content-)items use classes derived from it ... \$\endgroup\$