【问题标题】:Replace a collection item using Linq使用 Linq 替换集合项
【发布时间】:2009-04-14 23:42:04
【问题描述】:

如何在以下特定场景中使用 Linq 查找和替换属性:

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; }
    }
}

感谢您提前提供帮助。

【问题讨论】:

  • 您使用的是什么 PropertyBag?我认为.Net BCL 中没有。我问是因为“属性”吸气剂可能是进行克隆的人,因此你不能做你想做的事情。
  • Jonathan,这是我自己的自定义 PropertyBag 类。上面的代码有效,因为我没有替换 Property[] 数组中的整个项目。代码中的注释说明: //TODO: Just copying values... 了解如何查找索引并替换值
  • 只是想知道您为什么不使用我的无 LINQ IndexOf() 解决方案……现在我知道了!我将答案从实例更正为静态方法。

标签: c# linq linq-to-objects .net-3.0


【解决方案1】:

不要使用 LINQ,因为它不会改进代码,因为 LINQ 旨在查询集合而不是修改它们。我建议以下。

// 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?

此外,我建议不要使用数组。考虑使用IDictionary<String, Property>。这将代码简化为以下内容。

this.Properties[name] = value;

请注意,这两种解决方案都不是线程安全的。


一种特殊的 LINQ 解决方案 - 你看,你不应该使用它,因为整个数组将被一个新的替换。

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

【讨论】:

  • “不要使用LINQ,因为它不会改进代码”没有道理,这句话没用
  • @danbruc:不幸的是,使用 [I]Dicitonary 不是选项,因为它不可序列化......必须将其保留为数组......是的...... IndexOf() 似乎是一个合理的解决方案...... . 但我只是希望可能是我做错了什么,而 Linq 确实有办法做到这一点......
【解决方案2】:

[注意:此答案是由于对问题的误解 - 请参阅此答案的 cmets。显然,我有点密集:(] 您的“属性”是类还是结构?

我通过了这个测试:

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);
}

我想知道为什么 getter 返回一个“属性”而不是任何数据类型 .Value,但我仍然很好奇为什么你看到的结果与我不同。

【讨论】:

  • 这是一个类... 从上面重新粘贴评论:上面的代码有效,因为我没有替换 Property[] 数组中的整个项目。代码中的注释说明: //TODO: Just copying values... 了解如何查找索引并替换值
  • 嗨,乔纳森,非常感谢您抽出时间提供帮助。不是一个忘恩负义的白痴,你看... :)
  • 你能粘贴更多代码吗?我发布的代码对我有用,这是我能想到的唯一能让它像你描述的那样工作的东西。
  • 重点如下:“[...]Single().Value = value.Value;”只是更新属性的值,但不会将数组中的属性对象替换为提供的对象。这将需要类似“[...]Single() = value;”的东西。显然这不起作用 - LINQ 不支持
  • 修改收藏。您必须构建一个新的并用它替换旧的 - 请参阅我的答案中的示例 - 但这不是一个聪明的解决方案。
猜你喜欢
  • 1970-01-01
  • 2015-01-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 2021-04-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多