【问题标题】:Run a method on all objects within a collection对集合中的所有对象运行方法
【发布时间】:2009-05-29 21:22:52
【问题描述】:

所以我有一个从 Bloops 集合创建的 Razzies 集合。我使用 Linq 查询检索此集合。参考:Linq Select Certain Properties Into Another Object?查询。

我想知道是否可以在返回集合之前,甚至在返回集合之后,在所有新创建的 Razzies 上运行一个方法,而无需使用 for 循环。

我试过这个:

Dim results = From item In bloops _
              Select New Razzie() With _
              { _
                  .FirstName = item.FirstName, _
                  .LastName = item.LastName _
              }.UpdateAddress(item.Address)

但它什么也没返回。

【问题讨论】:

    标签: c# vb.net linq .net-3.5 ienumerable


    【解决方案1】:

    Russ,这可能会满足您的需求。这是一个非常简单的方法。如果这不是您想要的,请扩展您的问题。

    这将在您枚举每个元素时在每个元素上运行该方法。在您枚举之前,它将不会运行该方法,但您可以放心地知道该方法将在您使用数据之前运行。

    编辑由于您使用的是密封的第 3 方类,因此请使用扩展方法。这就是他们的目的。 ;) 修改代码以使用扩展方法。

    class MyArgs { }
    class Razzie //pretend this is a 3rd party class that we can't edit
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
    static class RazzieExtensions
    {
        public static Razzie MyMethod(this Razzie razzie, MyArgs args)
        {
            razzie.FirstName = razzie.FirstName.ToUpper();
            return razzie;
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            var bloops = new List<Razzie>
                {
                    new Razzie{FirstName = "name"},
                    new Razzie{FirstName = "nAmE"}
                };
            var myArgs = new MyArgs();
            var results = from item in bloops
                          select new Razzie
                          {
                              FirstName = item.FirstName,
                              LastName = item.LastName
                          }.MyMethod(myArgs);
    
            foreach (var r in results)
                Console.WriteLine(r.FirstName);
            Console.ReadKey();
        }
    }
    

    【讨论】:

    • 这个“会”工作,但在我的真实代码中,Razzie 类是我没有源代码的库的一部分,因此“MyMethod”是一个无效并且什么都不返回。
    • 哦,那我有两个词给你:扩展方法
    • 或等待...“没有来源”或“没有来源并且被密封”?如果您根本没有源代码,只需从 Razzie 继承并扩展它即可。但是,如果该类是密封的,请使用扩展方法。
    【解决方案2】:

    在初始处理后使用 foreach 循环是执行此操作的正常方法。如果您不想使用 foreach 循环,则需要定义自己的扩展方法来处理这种情况。

    【讨论】:

    • 我唯一的问题是我需要访问原始 bloop 类的属性(我更新了我的代码以反映)所以我将被限制为嵌套循环?在那种情况下,为了提高性能,我需要一起摆脱 linq 调用?
    【解决方案3】:

    我不确定你所说的 RunVoid 是什么意思。 Void 建议没有返回,但您将结果分配给一个值。

    您是否 RunVoid 对每个项目执行一个方法,然后返回原始集合?如果是这样,则没有内置方法,但您可以像这样添加一个。

    <Extension>
    Public Function RunVoid(Of T)(source As IEnumerable(Of T), del As Action(Of T) As IEnumerable(Of T)
      For Each cur in source
        del(cur)
      Next
      return source
    End Function
    

    【讨论】:

    • 是的,我正在尝试对每个项目运行该方法,然后返回原始集合。原因是该方法设置了一些我无法直接访问的“只读”属性。所以你是说我陷入了循环?
    • @Russ,您一次只能定义循环。现在您已经定义了 RunVoid,您可以为任何实现 IEnumerable(Of T) 的集合调用它。如果您将其粘贴到应用程序的模块中,您的示例应该可以编译并运行
    【解决方案4】:

    为什么不以正常的、未经评估的方式这样做呢?你可以用扩展方法做很多花哨的事情......但是你可能会通过使用扩展方法执行更新来打破纯度规则......这也让事情变得难以理解。试试这个:

    var results = from ... select new { Address = item.Address, Razzie = new Razzie { ... }}
    
    foreach (var result in results)
    {
        result.Razzie.UpdateAddress(result.Address);
    }
    

    【讨论】:

    • 因为我需要 item.Address 作为我的输入,因为 Address 属性是只读的。
    • 我的例子说明了这一点。
    【解决方案5】:

    如果您希望抽象出 foreach 循环,我只需为 IEnumerable 编写一个扩展方法,该方法复制 List 的 ConvertAll 和 ForEach 方法,如下所示:

    public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Converter<T, TOutput> converter)
    {
        if (converter == null)
            throw new ArgumentNullException("converter");
    
        List<TOutput> list = new List<TOutput>();
    
        foreach (T item in collection)
        {
            list.Add(converter(item));
        }
    
        return list;
    }
    
    public static void ForEach<T>(this IEnumerable<T> collection, Action<T> action)
    {
        foreach (T item in collection)
        {
            action(item);
        }
    }
    

    然后你可以调用类似的东西:

    bloops
        .ConvertAll(bloop => new Razzie()
                                { 
                                    FirstName = bloop.FirstName, 
                                    Lastname = bloop.LastName 
                                })
        .ForEach(razzie => razzie.UpdateAddress());
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-02
      • 1970-01-01
      • 2013-01-31
      • 2021-02-20
      • 1970-01-01
      • 2012-05-16
      • 2014-06-23
      相关资源
      最近更新 更多