开发者

Returning multiple objects and enumerate over it

开发者 https://www.devze.com 2023-04-05 17:33 出处:网络
I have a method which returns a WorkInfo 开发者_如何学JAVAobject. It has 2 properties CompanyName and WorkLocation.

I have a method which returns a WorkInfo 开发者_如何学JAVAobject. It has 2 properties CompanyName and WorkLocation.

It might happen that a person has worked at multiple companies. In this case i want to

  1. Return an array of WorkInfo object

  2. After the WorkInfo object is returned to calling method, i need to enumerate over it in following way

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

How do i achieve this in C# ?

UPDATE : All i need to do is return a collection of multiple objects of same type and loop over it using ForEach.

eg A datatable returns a collection of datarows and we can loop over it using ForEach(Datarow dr in datatable.Rows)

Similarly, what exactly should i do to return a collection of "WorkInfo" objects which i can loop over using ForEach ?


Here is another attempt:

Notes: quick code -- not tested -- I used your name conventions (ick CamelCase) etc.

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

Here is some code that I believe solves your problem:

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
  }

}


are you asking for some pseudo code like this?

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

  return result; 
}

and then:

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


Another solution again, by me is cutest :) , is to make something like this, a pseudocode:

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

and somewhere in the code just write exactly what you want:

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

The beauty of this, that by avoiding esplisitly implementing IEnumerable you have strong type control already during compialtion, as you implement your own enumerator.


Your desired design is, to say the least, convoluted. You can accomplish this by implementing an ad-hoc singly linked list - having a ref to the next WorkInfo in the WorkInfo structure. Then you return a WorkInfo, which might or might not contain a ref to another WorkInfo, and so on. The last item in the list has a null. Then implement IEnumerable in WorkInfo, if you insist on having a foreach() loop. If not, then the enumeration might be of the form:

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

Disclaimer: if you do that abomination instead of returning a good old collection of WorkInfos, God might just kill a kitten.


If I am understanding correctly, you might be able to do what you are doing using a linq query. This is not tested so don't hate me :)

...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();

Not 100% sure if this is what you are looking for or not, but hope it helps, even if just to get you thinking.


It sounds like your confusion is arising because you think you need two functions:

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

and

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

But you don't need both. You can write just one function to handle both cases.

Fundumentally, foreach takes an IEnumerable (e.g. an array, a list, a result from a Linq query), and loops over it.

An IEnumerable can enumerate zero, one, or many objects. You can think about this as the enumeration containing that many objects. With a list or an array, this makes a lot of sense.

To support returning just a single company, you can just return an IEnumerable (list or array) of size 1.

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
}

If you need your code to handle a special case when the function returns just a single result, then simply check the .Count or .Length member.

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

But unless you really need single company/multi-company to be treated differently, then I suggest you remove the length check entirely, and just write one set of code. This will be easier to maintain and debug in the future.


Others have already shown that you can just make your function return an array or list and foreach on it. It will work just as well if there is a single item.

If you have to retrieve them one at a time, you could also implement the enumerating logic yourself:

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

then:

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


This is how I do it.

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

精彩评论

暂无评论...
验证码 换一张
取 消