15

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?

1
  • You probably want to make it clear in the question whether the (possibly multiple) types of T are unknown at compile time or not. If they are known then Ulrik's answer makes sense, i.e. stop casting and force the argument type (perhaps with several overloads). If it is not known you must use reflection, in some form, and Marks answer shows thesimplest and likely best way to achieve this. Commented Aug 18, 2009 at 11:08

5 Answers 5

8

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.

Sign up to request clarification or add additional context in comments.

4 Comments

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.
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
what if the class is static?
@demodave then the inst is null
7

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)

Comments

2

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.

3 Comments

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.
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.
In any case, thanks for the comment - non-generic IEnumerable is a fine choice too.
2

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.

Comments

0

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.