Ivan-Mark Debono
Ivan-Mark Debono

Reputation: 16290

How to assign a value to a property using an expression?

I have a class:

public class Item { 
    public string Name { get; set; }
    public object Value { get; set; }
}

And a collection of this class:

ICollection<Item> items;

Currently I have the following:

var item = items.Where(x => x.Name == "id").FirstOrDefault();
if (item != null)
    item.Value = 1;

var item = items.Where(x => x.Name == "name").FirstOrDefault();
if (item != null)
    item.Value = "Username";

//etc... for a number of items

Is it possible to an Expression and inline function to achieve the above but in much less and cleaner code?

Something like:

items.Set(x => x.Name == "id", value = 1);
items.Set(x => x.Name == "name", value = "username");

Upvotes: 0

Views: 165

Answers (4)

Maciej
Maciej

Reputation: 7961

With slight addition to your class you can do it like this:

items.FirstOrDefault(x => x.Name == "id")?.SetValue(1);

Null-conditional operator ?. (aka Elvis operator) protects you from the default/null value while calling SetValue(1) but it does not allow for an assignment i.e. you cannot use property with it.

Your class will need SetValue method:

public void SetValue(object arg)
{
    Value = arg;
}

Upvotes: 1

Neville Nazerane
Neville Nazerane

Reputation: 7019

your syntax items.Set(x => x.Name == "id", value = 1); doesn't look valid. But you can use items.Set(x => x.Name == "id", value : 1); or items.Set(x => x.Name == "id", 1); if you use this:

public static class ItemExtensions
{

    public static void Set(this ICollection<Item> items, Func<Item, bool> predicate, object value)
    {
        var item = items.FirstOrDefault(predicate);
        if (item != null)
            item.Value = value;
    }

}

Explanation

  1. You are looking for a function for an existing class ICollection. So, you would need to create an extension function.
  2. You are trying to pass something to the Linq Where function. Check the exact data type passed into the where. You would notice its Func<TSource, bool> predicate. In this case, we know TSource is Item.
  3. You can also have this predicate directly inside FirstOrDefault

Upvotes: 0

koryakinp
koryakinp

Reputation: 4125

You can do something like that:

public static class Extensions
{
    public static void Set<T>(
        this ICollection<T> source, 
        Func<T, bool> predicate, 
        Action<T> action)
    {
        var item = source.FirstOrDefault(predicate);
        if(item != null)
        {
            action(item);
        }
    }
}

Usage:

var collection = new List<User>()
{
    new User { Name = "Pavel", Id = 1 },
    new User { Name = "Anna", Id = 2}
};

collection.Set(q => q.Id == 1, w => w.Name = "Jacob");

Upvotes: 2

Phiter
Phiter

Reputation: 14992

I can think of a solution using .ToList() and .ForEach(), but that is not very readable.

using System;
using System.Linq;
using System.Collections.Generic;

public class Item { 
    public string Name { get; set; }
    public object Value { get; set; }
}

public class Program
{
    public static void Main()
    {
        var items = new List<Item>();
        items.Add(new Item(){
            Name = "test",
            Value = 2
        });
        items.Add(new Item(){
            Name = "id",
            Value = 0
        });

        items.Where(i => i.Name == "id").ToList().ForEach(i => i.Value = 1);
        Console.WriteLine(items[1].Name + " : " + items[1].Value);
    }
}

Link to fiddle: https://ideone.com/7m66rg

Upvotes: 0

Related Questions