tags:

views:

171

answers:

4

I don't even think I have the question correct as I am just starting with generics and my knowledge isn't very great.

Say I have the following method:

public class Wrapper
{
    public List<TInfoType> GetInfo<TInfoType>(Array data, EdmCmd edmCmd)
    {
     switch (edmCmd.meCmdType)
     {
        case EdmCmdType.EdmCmd_PostAdd:
            List<EdmCmdPostAddInfo> info = new List<EdmCmdPostAddInfo>();
            foreach (EdmCmdData item in data)
            {
                info.Add(new EdmCmdPostAddInfo(item.mlObjectID1, item.mlObjectID2, item.mbsStrData1, item.mlLongData1));
            }
            return info;
            break;                
        default:
            break;
     }
    }
}

And I would like to call the method like:

List<EdmCmdPostAddInfo> info = wrapper.GetInfo<EdmCmdPostAddInfo>(data, edmCmd)

What is the correct way to do this? I am getting the error:

Cannot implicitly convert type 'System.Collections.Generic.List<EPDM.Utils.EdmCmdPostAddInfo>' to 'System.Collections.Generic.List<TInfoType>'

I am doing this because the EdmCmd struct that is passed to the method has various members that are generically named. It's difficult to remember what the members represent for each CmdType, so I am wrapping them in a more meaningful struct.

A: 

I think I see what you're trying to do, and it's not really possible to do it like you want to in C# 3 and previous version. This is a feature of C# 4 though, but you'll have to wait for a few months for that to go RTM.

Dave Markle
So I basically need to create a GetInfo() method for each type I want to return? Bummer.
ehcanadian
Or you could just return the base type, and then on the calling function, filter out the type you want by using the .OfType<DerivedType>() extension method (I think this is in System.Linq)
Dave Markle
+2  A: 

if you use

TInfoType[] data

instead of

Array data

as the parameter, then you can use

List<TInfoType> info = new List<TInfoType>();

intead of

List<EdmCmdPostAddInfo> info = new List<EdmCmdPostAddInfo>();

and then you don't need to do the new (instead you just use the objects passed in data). I hope this gives you the starting point.

Nestor
I don't have control over what is in the Array. It's already filled with EdmCmdData items. (I think I know what you're saying.)
ehcanadian
+1  A: 
public class Wrapper
{
   public List<TInfoType> GetInfo<TInfoType>(Array data, EdmCmd edmCmd)
   {
      List<object> info = new List<object>();

      switch (edmCmd.meCmdType)
      {
        case EdmCmdType.EdmCmd_PostAdd:
          foreach (EdmCmdData item in data)
          {
            info.Add(new EdmCmdPostAddInfo(item.mlObjectID1, item.mlObjectID2, item.mbsStrData1, item.mlLongData1));
          }
          break;                
        default:
          break;
      }

      return info.OfType<TInfoType>().ToList();
   }
}

Assuming all of your new ECmd* structures are truly structs and not classes with a hierarchy, you can create a List of objects and cast this after you've processed the passed in array.

Brett
+1  A: 

The fact that you're referencing a type explicitly in your generic method indicates that you've got trouble. There's no way for the compiler to know that a List<T> can contain an object of some type unless that type is T.

So create your list like this:

result = new List<T>();
foreach (EdmCmdData item in data)
{
   object o = new EdmCmdPostAddInfo(item.mlObjectID1, item.mlObjectID2, item.mbsStrData1, item.mlLongData1)
   result.Add((T)s);
}
return result;

This will throw an InvalidCastException at runtime if you invoke the method with the wrong type, but that's a problem you should already be expecting to have.

Robert Rossney