4

I have an extension method :

public static List<object> ToModelViewObjectList<ModelViewType>(this IEnumerable<object> source)
{

    List<ModelViewType> destinationList = new List<ModelViewType>();

    PropertyInfo[] ModelViewProperties = typeof(ModelViewType).GetProperties();
    foreach (var sourceElement in source)
    {
        object destElement = Activator.CreateInstance<ModelViewType>();
        foreach (PropertyInfo sourceProperty in sourceElement.GetType().GetProperties())
        {

            if (ModelViewProperties.Select(m => m.Name).Contains(sourceProperty.Name))
            {
                destElement.GetType().GetProperty(sourceProperty.Name).SetValue(destElement, sourceProperty.GetValue(sourceElement));
            }
        }
        destinationList.Add((ModelViewType)destElement);
    }

    return destinationList.Cast<object>().ToList();
}

And I have a method with a list of object that I want call extension methods in this method :

public void GridModel(IEnumerable<object> GridDataSource)        
{ 
   List<object> list = GridDataSource.ToModelViewObjectList<GridDataSource[0].GetType()>();
}

What should I write instead of GridDataSource[0].GetType() ?

Edited:

I have a method with a object parameter. I want to create a generic list of object type.

public void CreateListByNonGenericType(object myObject)
{
    Type objType = myObject.GetType();

    var lst = System.Collections.Generic.List < objType.MakeGenericType() > ();
}

What should I write instead of objType.MakeGenericType() ?

Siamak Ferdos
  • 3,181
  • 5
  • 29
  • 56
  • 3
    You need to write a type which is known at compile time. `GridDataSource[0].GetType()` will only be known at runtime. – dotnetom Nov 01 '14 at 07:59
  • 1
    So, There aren't any way to do this? – Siamak Ferdos Nov 01 '14 at 08:07
  • 1
    The only way I can think of is using reflection. – dotnetom Nov 01 '14 at 08:09
  • You can do it, but it's complicated, potentially slow, and raises the question of whether it's really a good idea in the first place. In your example, why can't you just use `object` as the type parameter, given that that's the parameter you're using everywhere else? – Peter Duniho Nov 01 '14 at 08:10
  • 1
    Generic type here, is a ModelView od MVC.Net that will fill and converted. Then as object list will be sent to View to render. – Siamak Ferdos Nov 01 '14 at 08:21
  • What does the extension method actually do? – Yuval Itzchakov Nov 01 '14 at 08:37
  • 1
    Extension method fill ViewModel from an IEnumerable. This code's are a part of a grid component for MVC.NET. I put full body of method in edit. – Siamak Ferdos Nov 01 '14 at 08:43
  • Looks like your goal is to make a deep copy of your list? If that is true [this might help](http://stackoverflow.com/questions/4226747/deep-copy-of-listt). – rene Nov 01 '14 at 09:15

3 Answers3

7

What should I write instead of GridDataSource[0].GetType() ?

Because you do not know the type at compile time, you have to perform everything in runtime. So you need to make a generic method from a method definition and call it. Something like following:

GridModel(IEnumerable<object> GridDataSource)        
{ 
   Type dataSourceElementType = GridDataSource[0].GetType();

   //MyExtension is a type where ToModelViewObjectList defined
   MethodInfo methodDefinition = typeof(MyExtension).GetMethod("ToModelViewObjectList");

   //https://msdn.microsoft.com/en-us/library/system.reflection.methodinfo.makegenericmethod
   MethodInfo method = methodDefinition.MakeGenericMethod(dataSourceElementType)

   //https://msdn.microsoft.com/en-us/library/a89hcwhh
   List<object> list = (List<object>)method.Invoke(GridDataSource, null);
}

But what you really want to do is to accept a type to ToModelViewObjectList as an argument instead of generic type parameter, like following, because you do not use ModelViewType outside of the function, as you return list of objects. Also, it will make your code clear.

public static List<object> ToModelViewObjectList(this IEnumerable<object> source, Type modelViewType)
{
    List<object> destinationList = new List<object>();

    PropertyInfo[] ModelViewProperties = modelViewType.GetProperties();
    foreach (var sourceElement in source)
    {
        object destElement = Activator.CreateInstance(modelViewType);
        foreach (PropertyInfo sourceProperty in sourceElement.GetType().GetProperties())
        {

            if (ModelViewProperties.Select(m => m.Name).Contains(sourceProperty.Name))
            {
                destElement.GetType().GetProperty(sourceProperty.Name).SetValue(destElement, sourceProperty.GetValue(sourceElement));
            }
        }
        destinationList.Add(destElement);
    }

    return destinationList;
}

And so you can call this extension method almost like you intended:

List<object> list = GridDataSource.ToModelViewObjectList(GridDataSource[0].GetType());

Also, it would be good to get the element type of GridDataSource using something else than getting first element's type.

hazzik
  • 13,019
  • 9
  • 47
  • 86
  • GetMethod can almost always be replaced by "dynamic", wich will generate faster and more readable code! – Zotta Jun 21 '15 at 07:07
5
public void CreateListByNonGenericType(object myObject)
{
    Type objType = myObject.GetType();
    Type listType = typeof(List<>).MakeGenericType(objType);

    //We can not use here generic version of the interface, as we
    // do not know the type at compile time, so we use the non generic 
    // interface IList which will enable us to Add and Remove elements from
    // the collection
    IList lst = (IList)Activator.CreateInstance(listType);
}
Behzad
  • 3,502
  • 4
  • 36
  • 63
hazzik
  • 13,019
  • 9
  • 47
  • 86
1

If you know your parameter is of "object" type only you can create list of "object" type. At the time of using list cast it to specific type like this.

public void CreateListByNonGenericType(object myObject)
{
     object objType = myObject.GetType();
     var lst = new List<object>();
     lst.Add(myObject);
}

But If you know the type of object at before calling the method you can use Generic method like this.

public void CreateListByNonGenericType<T>(T myObject, string s)
{
    var lst = new List<T>();
    lst.Add(myObject);
}
t j
  • 7,026
  • 12
  • 46
  • 66
Shankar
  • 256
  • 2
  • 12