将类型参数转换为T

3

我有点困惑如何从参数向方法传递类型参数。

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

        ...........

我尝试了以下方法,但它们也都失败了;
XElement xmloutput = XElementSerialiser.ToXElement<(T)type>(value);

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

显然,这段代码可以编译通过,但没有多大意义。
XElement xmloutput = XElementSerialiser.ToXElement<Type>(value);
3个回答

7

泛型实例化(即在签名中添加<T>)是一种编译时构造,而Type对象存在于运行时。

正如D Stanley所建议的那样,最好将整个方法设置为泛型,而根本不需要传递Type对象。
但是,如果无法这样做,您可以创建一个带有非泛型接口的泛型工厂,并动态地创建其实例。就像这样:

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

为了提高性能,您可能还希望缓存 factory 实例。
更新:将其制作成了一个博客文章

很不幸,在你的博客文章中所述的情况下,如果你试图从一个接受类型参数的静态方法调用一个通用的静态方法,会有很多额外的开销。 - Ian Kemp
与什么相比,开销太大了? - Fyodor Soikin
在编写和实例化额外类以及可能缓存的方面存在很多开销。我并不是说这是一个不好的解决方案,只是如果像调用非泛型方法一样简单地执行某些简单操作(与相反情况相比,后者很容易),那就太好了。 - Ian Kemp
从泛型方法中调用非泛型方法很简单,你只需要直接调用即可。 - Fyodor Soikin

4

您可以使用泛型来实现,但是能否将WriteToStreamAsync变为泛型方法?

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

1
我原本认为可以这样做,但似乎它可能会覆盖 System.Net.Http.Formatting.MediaTypeFormatter 中的某些内容,所以可能不是一个选项... - Chris

0

我同意D Stanley的答案,但是如果你想让编译器为你推断要序列化的对象类型,这样每次使用该方法时就不必指定它,那么请使用以下代码:

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

1
是的,我可以重载这个方法,但我仍然需要以某种方式将类型转换为T。 - wonea
你现在不需要传递Type了。编译器会为你推断出类型。你只需要调用WriteToStreamAsync(serializeThis, stream, ...)即可。 - Farhad Alizadeh Noori

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接