Vyas Bharghava
Vyas Bharghava

Reputation: 6510

Replace a collection item using Linq

How do I find and replace a property using Linq in this specific scenario below:

public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
    public Property[] Properties { get; set; }

    public Property this[string name]
    {
        get { return Properties.Where((e) => e.Name == name).Single(); }
        //TODO: Just copying values... Find out how to find the index and replace the value 
        set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
    }
}

Thanks for helping out in advance.

Upvotes: 4

Views: 18008

Answers (2)

Daniel Brückner
Daniel Brückner

Reputation: 59645

Do not use LINQ because it will not improve the code because LINQ is designed to query collection and not to modify them. I suggest the following.

// Just realized that Array.IndexOf() is a static method unlike
// List.IndexOf() that is an instance method.
Int32 index = Array.IndexOf(this.Properties, name);

if (index != -1)
{
   this.Properties[index] = value;
}
else
{
   throw new ArgumentOutOfRangeException();
}

Why are Array.Sort() and Array.IndexOf() methods static?

Further I suggest not to use an array. Consider using IDictionary<String, Property>. This simplifies the code to the following.

this.Properties[name] = value;

Note that neither solution is thread safe.


An ad hoc LINQ solution - you see, you should not use it because the whole array will be replaced with a new one.

this.Properties = Enumerable.Union(
   this.Properties.Where(p => p.Name != name),
   Enumerable.Repeat(value, 1)).
   ToArray();

Upvotes: 6

Jonathan Rupp
Jonathan Rupp

Reputation: 15762

[note: this answer was due to a misunderstanding of the question - see the comments on this answer. Apparently, I'm a little dense :(] Is your 'Property' a class or a struct?

This test passes for me:

public class Property
{
    public string Name { get; set; }
    public string Value { get; set; }
}
public interface IPropertyBag { }
public class PropertyBag : IPropertyBag
{
    public Property[] Properties { get; set; }

    public Property this[string name]
    {
        get { return Properties.Where((e) => e.Name == name).Single(); }
        set { Properties.Where((e) => e.Name == name).Single().Value = value.Value; }
    }
}

[TestMethod]
public void TestMethod1()
{
    var pb = new PropertyBag() { Properties = new Property[] { new Property { Name = "X", Value = "Y" } } };
    Assert.AreEqual("Y", pb["X"].Value);
    pb["X"] = new Property { Name = "X", Value = "Z" };
    Assert.AreEqual("Z", pb["X"].Value);
}

I have to wonder why the getter returns a 'Property' instead of whatever datatype .Value, but I'm still curious why you're seeing a different result than what I am.

Upvotes: 0

Related Questions