我开始使用.NET中的动态对象,我无法弄清楚如何做某事。

我有一个从动态object继承的类,我覆盖了tryInvokemember method。

e.g。

class MyCustomDynamicClass : DynamicObject
{
    public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
    {
        // I want to know here the type of the generic argument
    }
}
.

和在该方法内,我想知道调用中的通用参数的类型(如果有)。

e.g。 如果我调用以下代码,我希望在我的动态对象的汇编方法内获取system.boolean和system.int32的值

dynamic myObject = new MyCustomDynamicClass();
myObject.SomeMethod<bool>("arg");
myObject.SomeOtherMethod<int>("arg");
.

当前如果我在汇级方法内放置一个断点,我可以获得正在调用的方法的名称(“somemethod”和“某些情况下”,以及参数的值,但不是通用类型)。

如何获得这些值?

谢谢!

有帮助吗?

解决方案

Actually I looked through the hierarchy of the binder and found a property with the needed values in the internal fields of the object.

The problem is that the property isn't exposed because it uses C#-specific code/classes, therefore the properties must be accessed using Reflection.

I found the code in this japanese blog: http://neue.cc/category/programming (I don't read any japanese, therefore I'm not sure if the author actually describes this same issue

Here's the snippet:

var csharpBinder = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");
var typeArgs = (csharpBinder.GetProperty("TypeArguments").GetValue(binder, null) as IList<Type>);

typeArgs is a list containing the types of the generic arguments used when invoking the method.

Hope this helps someone else.

其他提示

A bit of googling and I have quite generic solution for .NET and Mono:

/// <summary>Framework detection and specific implementations.</summary>
public static class FrameworkTools
{
    private static bool _isMono = Type.GetType("Mono.Runtime") != null;

    private static Func<InvokeMemberBinder, IList<Type>> _frameworkTypeArgumentsGetter = null;

    /// <summary>Gets a value indicating whether application is running under mono runtime.</summary>
    public static bool IsMono { get { return _isMono; } }

    static FrameworkTools()
    {
        _frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter();
    }

    private static Func<InvokeMemberBinder, IList<Type>> CreateTypeArgumentsGetter()
    {
        if (IsMono)
        {
            var binderType = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.CSharpInvokeMemberBinder");

            if (binderType != null)
            {
                ParameterExpression param = Expression.Parameter(typeof(InvokeMemberBinder), "o");

                return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
                    Expression.TypeAs(
                        Expression.Field(
                            Expression.TypeAs(param, binderType), "typeArguments"),
                        typeof(IList<Type>)), param).Compile();
            }
        }
        else
        {
            var inter = typeof(Microsoft.CSharp.RuntimeBinder.RuntimeBinderException).Assembly.GetType("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");

            if (inter != null)
            {
                var prop = inter.GetProperty("TypeArguments");

                if (!prop.CanRead)
                    return null;

                var objParm = Expression.Parameter(typeof(InvokeMemberBinder), "o");

                return Expression.Lambda<Func<InvokeMemberBinder, IList<Type>>>(
                    Expression.TypeAs(
                        Expression.Property(
                            Expression.TypeAs(objParm, inter),
                            prop.Name),
                        typeof(IList<Type>)), objParm).Compile();
            }
        }

        return null;
    }

    /// <summary>Extension method allowing to easyly extract generic type arguments from <see cref="InvokeMemberBinder"/>.</summary>
    /// <param name="binder">Binder from which get type arguments.</param>
    /// <returns>List of types passed as generic parameters.</returns>
    public static IList<Type> GetGenericTypeArguments(this InvokeMemberBinder binder)
    {
        // First try to use delegate if exist
        if (_frameworkTypeArgumentsGetter != null)
            return _frameworkTypeArgumentsGetter(binder);

        if (_isMono)
        {
            // In mono this is trivial.

            // First we get field info.
            var field = binder.GetType().GetField("typeArguments", BindingFlags.Instance |
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static);

            // If this was a success get and return it's value
            if (field != null)
                return field.GetValue(binder) as IList<Type>;
        }
        else
        {
            // In this case, we need more aerobic :D

            // First, get the interface
            var inter = binder.GetType().GetInterface("Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder");

            if (inter != null)
            {
                // Now get property.
                var prop = inter.GetProperty("TypeArguments");

                // If we have a property, return it's value
                if (prop != null)
                    return prop.GetValue(binder, null) as IList<Type>;
            }
        }

        // Sadly return null if failed.
        return null;
    }
}

Have fun. By the way Impromptu is cool, but I can't use it.

The open source framework Dynamitey can call properties that internal/protected/private using the DLR and thus works with Silverlight. But it get's a little tricky with interface explicit members as you have to use the actual full name of the member on the the type, rather than the interface member name. So you can do:

var typeArgs = Dynamic.InvokeGet(binder, "Microsoft.CSharp.RuntimeBinder.ICSharpInvokeOrInvokeMemberBinder.TypeArguments")
     as IList<Type>;
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top