wonea
wonea

Reputation: 4969

Convert Type parameter to T

I'm a little stumped on how to pass in a type argument to a Method, from a parameter.

public class MyNamespaceXmlFormatter : XmlMediaTypeFormatter
{
    public override Task WriteToStreamAsync(Type type, object value, 
                                            Stream writeStream, HttpContent content, 
                                            TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
    {
        XElement xmloutput = XElementSerialiser.ToXElement<type>(value);

        ...........

I've tried the following, but these fail as well;

XElement xmloutput = XElementSerialiser.ToXElement<(T)type>(value);

XElement xmloutput = XElementSerialiser.ToXElement<typeof(type)>(value);

Obviously this compiles, but makes little sense;

XElement xmloutput = XElementSerialiser.ToXElement<Type>(value);

Upvotes: 3

Views: 993

Answers (3)

Fyodor Soikin
Fyodor Soikin

Reputation: 80765

Generic instantiation (i.e. adding <T> to signature) is a compile-time construct, while Type object exists at runtime.

It would be preferable, as D Stanley suggested, to make the whole method generic and not pass a Type object at all.
However, if you're unable to do that, you can make yourself a generic factory with non-generic interface, and create instances of it dynamically. Like so:

interface IFactory {
    XElement ToXElement( object value );
}

class Factory<T> : IFactory {
    public XElement ToXElement( object value ) { 
        return XElementSerialiser.ToXElement<T>( value ); 
    }
}

public override Task WriteToStreamAsync( Type type, object value, 
                                    Stream writeStream, HttpContent content, 
                                    TransportContext transportContext, System.Threading.CancellationToken cancellationToken) {
    var factory = Activator.CreateInstance( typeof( Factory<> ).MakeGenericType( type ) ) as IFactory;
    return factory.ToXElement( value );
}

For performance reasons, you might also want to cache the factory instance.

UPDATE: made a blog post out of it.

Upvotes: 7

Farhad Alizadeh Noori
Farhad Alizadeh Noori

Reputation: 2306

I agree with D Stanley's answer but in case you want to have the compiler infer the type of the object to be serialized for you so you don't have to specify it each time you use the method use this:

public override Task WriteToStreamAsync<T>(T value, 
                                        Stream writeStream, HttpContent content, 
                                        TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
{
    XElement xmloutput = XElementSerialiser.ToXElement<T>(value);

Upvotes: 0

D Stanley
D Stanley

Reputation: 152616

You could do it using generics, but could you make WriteToStreamAsync generic instead?

public override Task WriteToStreamAsync<T>(object value, 
                                        Stream writeStream, HttpContent content, 
                                        TransportContext transportContext, System.Threading.CancellationToken cancellationToken)
{
    XElement xmloutput = XElementSerialiser.ToXElement<T>(value);

Upvotes: 4

Related Questions