tags:

views:

183

answers:

5

See i have a situation like this...

object myRoledata  = List<Roles>() --> (some list or Ienumerable type)

Now i have a generic method which creates an XML object from List<T> - Something like this..

public string GetXML<T>(object listdata)  
{  
    List<T> objLists = (List<T>)Convert.ChangeType(listData, typeof(List<T>));  
    foreach(var obj in listdata)   
    {  
        //logic to create xml  
    }  
}

Now in order to run this method I have to do like this:

string xml = GetXML<Roles>(myRoledata);

Now i dont know what Type may come to me to be passed to GetXML method. I have a method which will call GetXML for different Types e.g. Roles, Users etc

now i can get the Type within the List<> like this

Type genericType = obj.GetType().GetGenericArguments()[0];

but cannot pass it like this

string xml = GetXML<genericType>(myRoledata);

Is there anyway in which i can pass any genericTypes to GetXML method?

+5  A: 

To do that, you need to use reflection;

typeof(SomeClass).GetMethod("GetXML").MakeGenericMethod(genericType)
         .Invoke(inst, new object[] {myRoleData});

where inst is null if it is a static method, this for the current instance (in which case you can also use GetType() instead of typeof(SomeClass)), or the target object otherwise.

Marc Gravell
But isn't this fundamentally wrong? By invoking the method this way, there is really no reason to use generics at all, because you throw away the type checks, and get all your errors at runtime.
Ulrik Rasmussen
My intpretation of the question is that they wanted to decouple it from generics. If that interpretation is incorrect, then your approach is clearly more appropriate. It depends on the scenario ;-p
Marc Gravell
+7  A: 

Since you cast your listdata parameter as a List< T> in the first line of your method, why don't you just change the method signature to

public string GetXML<T>(List<T> listdata)

That way, you don't have to use reflection to get the generic arguments.

EDIT: I see that you need to be able to accept IEnumerable collections, and not just lists. So, consider changing your method signature to

public string GetXML<T>(IEnumerable<T> listdata)
Ulrik Rasmussen
A: 

You have the right idea, but you are using the wrong method. Have a look at Type.MakeGenericType or MethodInfo.MakeGenericMethod. It will take a few more lines than your example, but it should be simple to solve.

GetGenericArguments() can be used to get the Roles type from a List. It's the differnt way around.

Btw: Looks like your implementing some kind of XML serialization. Make sure you check existing classes, before reinventing the wheel. ;-)

Achim
+2  A: 

I don't know your situation, but is it possible to rewrite your function as:

public string GetXML<T>(IEnumerable<T> listdata)  
{  
    foreach(var obj in listdata)   
    {  
        //logic to create xml  
    }  
}

Then it can be called as:

List<Role> myList;
GetXML(myList);

You can add type parameters as far back as needed to support it, till you get to somewhere that does know what the solid type is.

Matthew Scharley
+1  A: 

This is a problem you probably want to avoid solving. It is possible, via reflection, to call methods dynamically without statically resolving them - but it kind of defeats the whole point of the type-annotations.

Either do this:

public string GetXML(IEnumerable listdata) {  
    foreach(object obj in listdata)   
        //logic to create xml  
}

... which you now can call with any IEnumerable, or write it the "modern" way as:

public string GetXML(IEnumerable<object> listdata) {  
    foreach(object obj in listdata)   
        //logic to create xml  
}

... which you can call with any IEnumerable via GetXML(someEnumerable.Cast<object>()) and in C# 4.0 even directly by covariance.

If you need the type of an element runtime, you can get it using .GetType() on each element, or you can just pass it in as a parameter (and provide an override for backwards-compatibility):

public string GetXML(Type elementType, IEnumerable<object> listdata) {  
    foreach(object obj in listdata)   
        //logic to create xml  
}

public string GetXML<T>(IEnumerable<T> listdata) {
    return GetXML(typeof(T),listdata.Cast<object>());
}

Incidentally, if you're constructing XML, a string is probably a less robust return-type choice: if possible, you could work with something like an XElement instead - and get xml-validity guarantee's to boot.

Eamon Nerbonne
Actually, I'd advise against using `IEnumerable<object>` directly, atleast till C# 4.0; it likely won't do what you want it to, because of the lack of variance in type parameters. `IEnumerable` is more than usable.
Matthew Scharley
Well, specifically for IEnumerable, covariance is less of an issue due to the Linq `.Cast<>` operator. If you want to call a method with an `IEnumerable<object>` parameter and you have an `IEnumerable<T> myEnum` with some `T != object`, you can just do `myEnum.Cast<object>()` with little loss in readability and speed. The stylistic disadvantage of the non-generic `IEnumerable` is the lack of explicit `IDisposable` support, the fact that `System.Collections` is not in the default set of usings that VS.NET adds to new files, and that it's a less common idiom.
Eamon Nerbonne
In any case, thanks for the comment - non-generic `IEnumerable` is a fine choice too.
Eamon Nerbonne