sudhansu63
sudhansu63

Reputation: 6190

Pass property to a function in C#, EF

I have several methods with a common pattern, i want to write a generic function that will take the column name as input and give the same result.

private void Query138()
{
    var products = (from p in _context.Products
                    where p.Manufacturer == null
                    select p);
    foreach (var productItem in products)
    {
        productItem.Manufacturer = string.Empty;
        _context.UpdateProduct(productItem);
    }

}

private void Query139()
{
    var products = (from p in _context.Products
                    where p.ModelNumber == null
                    select p);
    foreach (var productItem in products)
    {
        productItem.ModelNumber = string.Empty;
        _context.UpdateProduct(productItem);
    }

}

i want to write a generic function that will take the column name as input for the above methods.

Example:

 private void Update(Expression<Fun<T,string>> pred = null)
        {
            //use the input column to select the data

            //use the input column to set the new value and update

        }

Upvotes: 2

Views: 732

Answers (3)

Zhuravlev A.
Zhuravlev A.

Reputation: 394

This should works:

class SomeClass
{
     public string prop1 { get; set; }
     public string prop2 { get; set; }
}

///...

private void Update<T, TReturn>(Expression<Func<T, TReturn>> expression) 
{
    MemberExpression body = (MemberExpression)expression.Body;
    var propName = body.Member.Name;
    var prop = typeof(SomeClass).GetProperty(propName);
    var products = (from p in contextProds
                    where prop.GetValue(p) == null
                    select p);
    ///...
}

Usage:

Update((SomeClass s) => s.prop1);
Update((SomeClass s) => s.prop2);

Where contextProds is like List<SomeClass> type. Also you can visit this: Get name of property as a string.

Upvotes: 1

Peter Aylett
Peter Aylett

Reputation: 780

You can specify a getter and use it to generate a setter. This can be achieved as follows:

private void Update(Expression<Func<Product, string>> getExpr)
{
    var value = Expression.Parameter(typeof(string), "value");
    var setExpr = Expression.Lambda<Action<Product, string>>(
        Expression.Assign(getExpr.Body, value), getExpr.Parameters[0], value);

    Func<Product, string> getter = getExpr.Compile();
    Action<Product, string> setter = setExpr.Compile();

    var products = (from p in _context.Products
                    where getter(p) == null
                    select p);
    foreach (var productItem in products)
    {
        setter(productItem, string.Empty);
        _context.UpdateProduct(productItem);
    }
}

And then called as follows:

Update( x => x.ModelNumber );

Upvotes: 0

Hyarus
Hyarus

Reputation: 952

You will need two expressions to achive this. One to get your value and the other to set it.

private void Update(Expression<Func<T, string>> getter, Expression<Action<T, string>> setter)
    {
        var products = (from p in _context.Products
                        where getter(p) == null
                        select p);
        foreach (var productItem in products)
        {
            setter(productItem, string.Empty);
            _context.UpdateProduct(productItem);
        }
    }

This way you can use i => i.[Your Attribute] and (i, o) => i.[Your Attribute] = o to call your function:

Update(i => i.[Your Attribute],(i, o) => i.[Your Attribute] = o); 

Or in your case:

Update(i => i.Manufacturer,(i, o) => i.Manufacturer = o); 
Update(i => i.ModelNumber,(i, o) => i.ModelNumber = o); 

Upvotes: 1

Related Questions