Get generic type of call to method in dynamic object

后端 未结 3 860
感动是毒
感动是毒 2021-02-07 08:49

I\'m starting to work with dynamic objects in .Net and I can\'t figure out how to do something.

I have a class that inherits from DynamicObject, and I override the TryIn

3条回答
  •  迷失自我
    2021-02-07 09:43

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

    /// Framework detection and specific implementations.
    public static class FrameworkTools
    {
        private static bool _isMono = Type.GetType("Mono.Runtime") != null;
    
        private static Func> _frameworkTypeArgumentsGetter = null;
    
        /// Gets a value indicating whether application is running under mono runtime.
        public static bool IsMono { get { return _isMono; } }
    
        static FrameworkTools()
        {
            _frameworkTypeArgumentsGetter = CreateTypeArgumentsGetter();
        }
    
        private static Func> 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>>(
                        Expression.TypeAs(
                            Expression.Field(
                                Expression.TypeAs(param, binderType), "typeArguments"),
                            typeof(IList)), 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>>(
                        Expression.TypeAs(
                            Expression.Property(
                                Expression.TypeAs(objParm, inter),
                                prop.Name),
                            typeof(IList)), objParm).Compile();
                }
            }
    
            return null;
        }
    
        /// Extension method allowing to easyly extract generic type arguments from .
        /// Binder from which get type arguments.
        /// List of types passed as generic parameters.
        public static IList 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;
            }
            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;
                }
            }
    
            // Sadly return null if failed.
            return null;
        }
    }
    

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

提交回复
热议问题