How Set Value a Property Selector Expression<Func<T,Tresult>>

How set value a property selector ExpressionFuncT,TResult

This works:

The following helper method converts a getter expression into a setter delegate. If you want to return an Expression<Action<T,TProperty>> instead of an Action<T,TProperty>, just don't call the Compile() method at the end.

Note: The code is from Ian Mercer's blog: http://blog.abodit.com/2011/09/convert-a-property-getter-to-a-setter/

    /// <summary>
/// Convert a lambda expression for a getter into a setter
/// </summary>
public static Action<T, TProperty> GetSetter<T, TProperty>(Expression<Func<T, TProperty>> expression)
{
var memberExpression = (MemberExpression)expression.Body;
var property = (PropertyInfo)memberExpression.Member;
var setMethod = property.GetSetMethod();

var parameterT = Expression.Parameter(typeof(T), "x");
var parameterTProperty = Expression.Parameter(typeof(TProperty), "y");

var newExpression =
Expression.Lambda<Action<T, TProperty>>(
Expression.Call(parameterT, setMethod, parameterTProperty),
parameterT,
parameterTProperty
);

return newExpression.Compile();
}

Property selector ExpressionFuncT. How to get/set value to selected property

The parameter would be an Expression<Func<Customer,string>> selector. Reading it can be via flat compile:

 Func<Customer,string> func = selector.Compile();

then you can access func(customer). Assigning is trickier; for simple selectors your could hope that you can simply decompose to:

var prop = (PropertyInfo)((MemberExpression)selector.Body).Member;
prop.SetValue(customer, newValue, null);

But more complex expressions would either need a manual tree walk, or some of the 4.0 expression node-types:

        Expression<Func<Customer, string>> email
= cust => cust.Email;

var newValue = Expression.Parameter(email.Body.Type);
var assign = Expression.Lambda<Action<Customer, string>>(
Expression.Assign(email.Body, newValue),
email.Parameters[0], newValue);

var getter = email.Compile();
var setter = assign.Compile();

How to set property value using Expressions?

You could cheat and make life easier with an extension method:

public static class LambdaExtensions
{
public static void SetPropertyValue<T, TValue>(this T target, Expression<Func<T, TValue>> memberLamda, TValue value)
{
var memberSelectorExpression = memberLamda.Body as MemberExpression;
if (memberSelectorExpression != null)
{
var property = memberSelectorExpression.Member as PropertyInfo;
if (property != null)
{
property.SetValue(target, value, null);
}
}
}
}

and then:

var myCustomerInstance = new Customer();
myCustomerInstance.SetPropertyValue(c => c.Title, "Mr");

The reason why this is easier is because you already have the target on which the extension method is invoked. Also the lambda expression is a simple member expression without closures. In your original example the target is captured in a closure and it could be a bit tricky to get to the underlying target and PropertyInfo.

How to set a value from an Expression for nested levels of depthness?

As I stated in the comments, it shouldn't be all that complicated. With the selector, just add an assignment to the expression. You'll just need to compile and run the expression.

public static TEntity ExecuteMagicSetter<TEntity, TProperty>(
this TEntity obj,
Expression<Func<TEntity, TProperty>> selector,
TProperty value)
{
var setterExpr = CreateSetter(selector);
setterExpr.Compile()(obj, value);
return obj;
}

private static Expression<Action<TEntity, TProperty>> CreateSetter<TEntity, TProperty>
(Expression<Func<TEntity, TProperty>> selector)
{
var valueParam = Expression.Parameter(typeof(TProperty));
var body = Expression.Assign(selector.Body, valueParam);
return Expression.Lambda<Action<TEntity, TProperty>>(body,
selector.Parameters.Single(),
valueParam);
}

Retrieving Property name from lambda expression

I found another way you can do it was to have the source and property strongly typed and explicitly infer the input for the lambda. Not sure if that is correct terminology but here is the result.

public static RouteValueDictionary GetInfo<T,P>(this HtmlHelper html, Expression<Func<T, P>> action) where T : class
{
var expression = (MemberExpression)action.Body;
string name = expression.Member.Name;

return GetInfo(html, name);
}

And then call it like so.

GetInfo((User u) => u.UserId);

and voila it works.

Convert ExpressionFuncTClass, TField to ExpressionFuncTClass, object

I concur completely to what Daisy wrote in its comments... Still you asked for something:

public UpdateExpressionBuilder<TClass> Add<TField>(Expression<Func<TClass, TField>> field, TField value)
{
var body = field.Body;

// Boxing for value types
if (typeof(TField).IsValueType)
{
body = Expression.Convert(body, typeof(object));
}

Expression<Func<TClass, object>> field2 = Expression.Lambda<Func<TClass, object>>(body, field.Parameters);

fieldsValues.Add(field2, value);
return this;
}

and then

var personUpdateExpression = new UpdateExpressionBuilder<Person>()
.Add(p => p.FirstName, "David")
.Add(p => p.MiddleName, "A")
.Add(p => p.Age, 30)
.Build();

Note that your example was string-only, but I've added an example for int.

In the end we rewrite the Expression. For reference types, nothing needs to be done other than changing the return type of the Func<>. For value types you need an explicit boxing.

Set value with func pointing to the property

You need to pass the new value for "MyProperty" as an argument to your Func

    Func<MyModel,int, int> func = (x, newValue) => 
{
x.MyProperty = newValue;
return newValue;
};

And use it like this:

    var m = new MyModel();
func(m, 2);

Alternatively, if you are not interested in the return value you can turn the Func into and Action:

Action<MyModel,int> func = (x, newValue) => x.MyProperty = newValue;

Also, you can capture the "MyModel" variable in a closure so that you don't pass the instance explicitly every time you want to change "MyProperty"'s value:

var myModel = new MyModel();    

Func<MyModel, Action<int>> getSetter = x =>
newValue=>x.MyProperty = newValue;

var setter = getSetter(myModel);

setter(3);
setter(4);

Apply Linq FuncT, TResult key selector at single element level

So something like:

public static IEnumerable<EntityIndex<T, Y>> IndexBy<T, Y>(this IEnumerable<T> entities, Func<T, Y> indexSelector) {
return entities.Select(e => new EntityIndex<T, Y> { Entity = e, IndexValue = indexSelector(e) });
}

Noting that generically defining EntityIndex with the TIndexType (called Y here) is important because you don't know ahead of time what the index is. The use of a generic allows Y to be an enumeration, thus the following would work as an index selector:

// Assuming Animal has attributes "Kingdom", "Phylum", "Family", "Genus", "Species"
// this returns an enumeration of EntityIndex<Animal, String[]>
var animalsClassified = someAnimals.IndexBy(a => new String[] { a.Kingdom, a.Phylum, a.Family, a.Genus, a.Species });

EDIT (Adding further detail):

Using the above, you can group the results by unique index value:

var animalClassifications = animalsClassified
.SelectMany(ac => ac.IndexValue.Select(iv => new { IndexValue = iv, Entity = ac.Entity }))
.GroupBy(kvp => kvp.IndexValue)

What I've described here, by the way, is (a very simplified form of) the MapReduce algorithm as popularized by Google. A distributed form of the same is commonly used for keyword identification in text search, where you want to build an index of (search term)->(list of containing documents).

How to cast ExpressionFuncT, DateTime to ExpressionFuncT, object

You can't just cast between them, as they're not the same kind of thing. However, you can effectively add a conversion within the expression tree:

using System;
using System.Linq.Expressions;

class Test
{
// This is the method you want, I think
static Expression<Func<TInput,object>> AddBox<TInput, TOutput>
(Expression<Func<TInput, TOutput>> expression)
{
// Add the boxing operation, but get a weakly typed expression
Expression converted = Expression.Convert
(expression.Body, typeof(object));
// Use Expression.Lambda to get back to strong typing
return Expression.Lambda<Func<TInput,object>>
(converted, expression.Parameters);
}

// Just a simple demo
static void Main()
{
Expression<Func<string, DateTime>> x = text => DateTime.Now;
var y = AddBox(x);
object dt = y.Compile()("hi");
Console.WriteLine(dt);
}
}

LINQ Expression to return Property value?

Easiest way to do this: Use LINQKit (Free, non-restrictive license)

Working version of code:

public static IEnumerable<T> SelectByParameterList<T, PropertyType>(this Table<T> items, IEnumerable<PropertyType> parameterList, Expression<Func<T, PropertyType>> propertySelector, int blockSize) where T : class
{
var groups = parameterList
.Select((Parameter, index) =>
new
{
GroupID = index / blockSize, //# of parameters per request
Parameter
}
)
.GroupBy(x => x.GroupID)
.AsEnumerable();

var selector = LinqKit.Linq.Expr(propertySelector);

var results = groups
.Select(g => new { Group = g, Parameters = g.Select(x => x.Parameter) } )
.SelectMany(g =>
/* AsExpandable() extension method requires LinqKit DLL */
items.AsExpandable().Where(item => g.Parameters.Contains(selector.Invoke(item)))
);

return results;
}

Example usage:

    Guid[] local_refill_ids = Refills.Select(r => r.Id).Take(20).ToArray();

IEnumerable<Refill> results = Refills.SelectByParameterList(local_refill_ids, r => r.Id, 10); //runs 2 SQL queries with 10 parameters each

Thanks again for all your help!



Related Topics



Leave a reply



Submit