【问题标题】:Returning multiple objects and enumerate over it返回多个对象并枚举它
【发布时间】:2011-11-18 04:03:27
【问题描述】:

我有一个返回WorkInfo 对象的方法。它有两个属性CompanyNameWorkLocation

一个人可能曾在多家公司工作过。在这种情况下,我想

  1. 返回WorkInfo对象数组

  2. WorkInfo对象返回给调用方法后,我需要通过以下方式枚举它

    foreach(WorkItem wRow in WorkInfo) 
    {
       string s1 = wRow.CompanyName ;
       string s2 = wRow.WorkLocation;
    }
    

我如何在 C# 中实现这一点?

更新: 我需要做的就是返回相同类型的多个对象的集合,然后使用 ForEach 对其进行循环。

例如,数据表返回数据行的集合,我们可以使用 ForEach(Datarow dr in datatable.Rows) 对其进行循环

同样,我应该怎么做才能返回可以使用 ForEach 循环的“WorkInfo”对象集合?

【问题讨论】:

  • 如何判断一个人是否在多家公司工作过?
  • 这里到底有什么问题?您只需让函数返回一个数组。我错过了什么吗?
  • 我猜 OP 正试图拥有一种可以返回 WorkInfo 或 WorkInfo 集合的方法。还有,吃她的蛋糕。
  • 更新了我的问题。希望这会有所帮助。
  • @Seva Alekseyev:没错,我想返回 WorkInfo 的集合。

标签: c#


【解决方案1】:

这是另一个尝试:

注意:快速代码——未经测试——我使用了你的命名约定(ick CamelCase)等。

public class WorkInfo
{
   public string CompanyName { Get; Set; };
   public string WorkLocation { Get; Set; };
}

public class Example
{

   public List<WorkInfo> GetAList()
   {
      List<WorkInfo> result = new List<WorkInfo>();

      result.Add(new WorkInfo { CompanyName = "MS", WorkLocation = "Redmond" });
      result.Add(new WorkInfo { CompanyName = "Google", WorkLocation = "New York" });
      result.Add(new WorkInfo { CompanyName = "Facebook", WorkLocation = "CA" });

      return result;
   }

   public UseAList()
   {
      foreach(WorkInfo wRow in  GetAList()) 
      {
        string s1 = wRow.CompanyName ;
        string s2 = wRow.WorkLocation;

        // process list elements s1 and s2
      }
   }
}

以下是一些我认为可以解决您的问题的代码:

workInfo = FunctionThatReturnsArray(..);

if (workInfo.Length == 1)
{
   // process single item at workInfo[0]
}
else
{
  foreach(WorkItem wRow in WorkInfo) 
  {
    string s1 = wRow.CompanyName ;
    string s2 = wRow.WorkLocation;

    // process list elements s1 and s2
  }

}

【讨论】:

  • if Length == 1 的原因是什么?这也不能在 foreach 中处理吗?为什么无用的代码重复?
  • @Davide - 基于我认为的问题,他想以与列表不同的方式处理单个案例。只是猜测,因为问题不是 100% 清楚。
  • @Anil - 那是你要找的吗?
  • @Hogan:是的。完美的。我有几个问题。这种方法的效率如何?还有其他替代方法吗?我相信为 CompanyName 和 WorkLocation 的每个条目创建一个对象将消耗更多资源。我有 JSON 格式的 CompanyName 和 WorkLocation 数据。我需要它以可以以强类型方式使用的方式返回。在对象 WorkInfo 数组中返回这些数据是我的想法。如果您有更好的方法,请告诉我。 P.S:在上面的代码中,“WorkItem”类型的定义在哪里?
  • @Anil - WorkItem 是一个错字。如果您必须遍历对象一次以创建列表,然后再一次使用列表,它将比仅遍历 json 对象慢,但没有其他方法可以创建更快的强类型 WorkInfo 数据.
【解决方案2】:

你要的是这样的伪代码吗?

public WorkItem[] GetWorkItems(Person p)
{
  WorkItem[] result = YourDatabaseLogicOrBusinessLogic.GetWorkItems(p);

  return result; 
}

然后:

foreach(WorkItem wRow in GetWorkItems(p1)) 
{
   string s1 = wRow.CompanyName ;
   string s2 = wRow.WorkLocation;
}

【讨论】:

  • 是的,我已经更新了我的问题。你能帮我详细介绍一下吗?
  • 是的,所以对我的示例数组进行循环,或者返回一个 Enumerable 或 List 并使用 foreach 对其进行循环
【解决方案3】:

另一个解决方案,对我来说是最可爱的:),就是制作这样的东西,一个伪代码:

 public class WorkInfoEnumerator
    {
        List<WorkItem > wilist= null;
        int currentIndex = -1;


        public MyClassEnumerator(List<WorkItem > list)
        {
            wilist= list;
        }

        public WorkItem Current
        {
            get
            {
                return wilist[currentIndex];
            }
        }

        public bool MoveNext()
        {
            ++currentIndex;
            if (currentIndex < wilist.Count)
                return true;
            return false;
        }   
    }


    public class WorkInfo
    {
        List<WorkItem > mydata = new List<WorkItem >() {.... }; //init here, for example
        public WorkInfoEnumerator GetEnumerator()
        {
            return new WorkInfoEnumerator(mydata);
        }
    }

在代码中的某处写正是你想要的:

     foreach(WorkItem wRow in WorkInfo) 
    {
       string s1 = wRow.CompanyName ;
       string s2 = wRow.WorkLocation;
    }

这样做的美妙之处在于,通过避免特别实现 IEnumerable,您在编译期间已经拥有强大的类型控制,因为您实现了自己的枚举器。

【讨论】:

    【解决方案4】:

    您想要的设计至少可以说是复杂的。您可以通过实现一个 ad-hoc 单链表来实现这一点 - 在 WorkInfo 结构中具有对下一个 WorkInfo 的引用。然后返回一个WorkInfo,它可能包含也可能不包含对另一个WorkInfo 的引用,依此类推。列表中的最后一项具有null。然后在 WorkInfo 中实现IEnumerable,如果你坚持要有一个foreach() 循环。如果不是,那么枚举可能是以下形式:

    for(;wRow != null; wRow = wRow.Next)    
    {
        string s1 = wRow.CompanyName; 
        //...
    }
    

    免责声明:如果您这样做可憎,而不是返回 WorkInfos 的旧收藏,上帝可能会杀死一只小猫。

    【讨论】:

      【解决方案5】:

      如果我理解正确,您也许可以使用 linq 查询来完成您正在做的事情。这未经测试所以不要恨我:)

      ...Get all workinfos for person and iterate over them,
      ...grouping by company name.
      ...Assuming you have an object called workInfos that contains
      ...the data returned from your datastore.
      List<WorkInfo> result = new List<WorkInfo>();
      result = (from wi in workInfos
                group wi on wi.CompanyName into gwi
                select new WorkInfo {
                    CompanyName = gwi.Key,
                    Location = gwi.Location
                }).ToList();
      

      不能 100% 确定这是否是您正在寻找的东西,但希望它有所帮助,即使只是为了让您思考。

      【讨论】:

        【解决方案6】:

        听起来你的困惑是因为你认为你需要两个函数:

        public WorkItem GetCompany(User user) { /* ... */ }
        

        public WorkItem[] GetCompanies(User user) { /* ... */ }
        

        但你不需要两者。你可以只写一个函数来处理这两种情况。

        从根本上说,foreach 接受 IEnumerable(例如数组、列表、Linq 查询的结果),然后循环遍历它。

        IEnumerable 可以枚举零个、一个或多个对象。您可以将其视为包含那么多对象的枚举。对于列表或数组,这很有意义。

        要支持只返回一个公司,您可以只返回一个大小为 1 的 IEnumerable(列表或数组)。

        public WorkItem[] GetCompanies(User user)
        {
            // Todo: some DB query here
            // if we get 5 results, return them as an array of size 5
            // If we get one result, return it as an array of size 1
        }
        

        如果您需要您的代码在函数只返回一个结果时处理特殊情况,则只需检查.Count.Length 成员。

        WorkItem[] result = GetCompanies(user);
        
        if(result.Length == 0)
        {
            // todo: is this an error?  If so, let the user know here
        }
        else if(result.Length == 1)
        {
            WorkItem theOnlyCompany = result[0];
            // todo: do something interesting here, for the 1-company case
        }
        else
        {
            foreach(WorkItem in result)
            {
                // todo: do something interesting here, for the multi-company case
            }
        }
        

        但是除非你真的需要区别对待单个公司/多个公司,那么我建议你完全去掉长度检查,只写一组代码。这将在未来更容易维护和调试。

        【讨论】:

        • 看起来很像我的回答:D
        • @Hogan:代码非常相似,是的。我添加了一个新答案,因为我想更深入地研究基本原理和工作原理。
        【解决方案7】:

        其他人已经表明,您可以让您的函数返回一个数组或列表并在其上进行 foreach。如果只有一个项目,它也能正常工作。

        如果您必须一次检索一个,您也可以自己实现枚举逻辑:

        public IEnumerable<WorkItem> WorkItems(Person p)
        {
            WorkItem item = GetAWorkItem(p);
            yield result item;
        }
        

        然后:

        foreach(WorkItem item in WorkItems()) 
        {
           string s1 = item.CompanyName;
           string s2 = item.WorkLocation;
        }
        

        【讨论】:

          【解决方案8】:

          我就是这样做的。

          public Tuple<int, int> ReturnMultipleValues()
          {
               return new Tuple<int,int>(1,2);
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-05-07
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多