如何将其转换为通用对象? [英] How to up-cast to a generic object?

查看:99
本文介绍了如何将其转换为通用对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类型为IRegistration []的Castle windsor注册组件数组。

I have an array of Castle windsor registration components of type IRegistration[]

在这种情况下, ComponentRegistration< T& :IRegistration

对于数组中的每个元素,
如果它可以上传到ComponentRegistration<>我想upcast它回到 ComponentRegistration< T> 并处理它。我将如何做到这一点?

For each element in my array, if it can be upcast to ComponentRegistration<> I would like to upcast it back to ComponentRegistration<T> and process it. How exactly would I do this?

我到达

foreach (var r in registrations) {
  if(typeof(ComponentRegistration<>).IsAssignableFrom(r.GetType())) {
    var cr = CAST r SOMEHOW
    DoStuff(cr);
  }


推荐答案

IRegistration [] 那么你是向下转换而不是向上转换。

Surely if you've got an IRegistration[] then you're downcasting rather than upcasting.

解决你的问题, DoStuff()看起来像什么?是否需要知道 ComponentRegistration< T> 的类型参数?如果没有,你最好创建一个非泛型的基类:

However, to get to your problem, what does DoStuff() look like? Does it need to know the type argument for ComponentRegistration<T>? If not, you might be best creating a non-generic base class:

public abstract class ComponentRegistration : IRegistration
{
    // Anything in the original API which didn't use T
}

public class ComponentRegistration<T> : ComponentRegistration
{
    // The bits which need T
}

然后你可以写:

foreach (var r in registrations)
{
    ComponentRegistration cr = r as ComponentRegistration;
    if (cr != null)
    {
        DoStuff(cr);
    }
}

如果你真的需要 DoStuff 要使用通用信息,您必须使用反射来获取适当的类型并调用它。如果可能,请避免:)

If you really need DoStuff to use the generic information, you'll have to use reflection to get the appropriate type and invoke it. Avoid if possible :)

编辑:好的,这里是反射谬误的例子。它不试图考虑通用接口,因为它变得更加漂亮。

Okay, here's an example of the reflection nastiness. It doesn't try to account for generic interfaces, as that gets even hairier.

using System;
using System.Reflection;

class Test
{   
    static void Main()
    {
        Delegate[] delegates = new Delegate[]
        {
            (Action<int>) (x => Console.WriteLine("int={0}", x)),
            (Action<string>) (x => Console.WriteLine("string={0}", x)),
            (Func<int, int>) (x => x + 1)
        };

        MethodInfo genericPerformAction = typeof(Test).GetMethod
                                                       ("PerformAction");

        foreach (Delegate del in delegates)
        {
            Type t = DiscoverTypeArgument(del, typeof(Action<>));
            if (t == null)
            {
                // Wrong type (e.g. the Func in the array)
                continue;
            }
            MethodInfo concreteMethod = genericPerformAction.MakeGenericMethod
                (new[] { t } );
            concreteMethod.Invoke(null, new object[] { del });
        }
    }

    public static void PerformAction<T>(Action<T> action)
    {
        Console.WriteLine("Performing action with type {0}", typeof(T).Name);
        action(default(T));
    }

    /// <summary>
    /// Discovers the type argument for an object based on a generic
    /// class which may be somewhere in its class hierarchy. The generic
    /// type must have exactly one type parameter.
    /// </summary>
    /// <returns>
    /// The type argument, or null if the object wasn't in
    /// the right hierarchy.
    /// </returns>
    static Type DiscoverTypeArgument(object o, Type genericType)
    {
        if (o == null || genericType == null)
        {
            throw new ArgumentNullException();
        }
        if (genericType.IsInterface ||
            !genericType.IsGenericTypeDefinition || 
            genericType.GetGenericArguments().Length != 1)
        {
            throw new ArgumentException("Bad type");
        }

        Type objectType = o.GetType();
        while (objectType != null)
        {
            if (objectType.IsGenericType &&
                objectType.GetGenericTypeDefinition() == genericType)
            {
                return objectType.GetGenericArguments()[0];
            }
            objectType = objectType.BaseType;
        }
        return null;
    }
}

EDIT:请注意 if 您处于所有成员都来自相关类的情况,如果您使用的是C#4,您可以使用动态绑定:

Note that if you're in a situation where all the members are derived from the relevant class, and if you're using C# 4, you can use dynamic binding:

using System;
using System.Reflection;

class Test
{   
    static void Main()
    {
        Delegate[] delegates = new Delegate[]
        {
            (Action<int>) (x => Console.WriteLine("int={0}", x)),
            (Action<string>) (x => Console.WriteLine("string={0}", x)),
            (Action<long>) (x => Console.WriteLine("long={0}", x)),
        };

        foreach (dynamic del in delegates)
        {
            // Yay for dynamic binding
            PerformAction(del);
        }
    }

    public static void PerformAction<T>(Action<T> action)
    {
        Console.WriteLine("Performing action with type {0}", typeof(T).Name);
        action(default(T));
    }
}

不幸的是,我不知道任何测试方式它是否将成功绑定到方法,而不仅仅是尝试它和捕获相关的异常(这将是严峻的)。也许埃里克会告诉我们:)

Unfortunately I don't know of any way of testing whether it's going to manage to bind to the method successfully without just trying it and catching the relevant exception (which would be grim). Maybe Eric will be able to tell us :)

这篇关于如何将其转换为通用对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆