在 C# 中使用反射获取具有单个属性或没有属性的方法

Get a method with a single or no attributes with Reflection in C#

我正在学习 Reflection,我正在研究一种可序列化的操作类型,它可以保存,然后加载和触发。可序列化操作支持不带参数或类型为 int、float、double、string 或 bool 的单个参数的方法。

所有 传递名称的方法要么具有上述类型的 一个属性,要么具有 根本没有属性 他们也可以有一个具有默认值的属性。 我的问题来了。首先,当我为具有重载的方法调用 target.GetType().GetMethod(methodName); 时,我得到一个 AmbiguousMatchException,如果我为具有单个可选参数的方法调用它,我得到一个 NULL。

所以我现在做的是从 try-catch 开始捕获 AmbiguousMatchException,然后告诉我给定的方法有重载。如果我得到一个异常,我开始尝试让方法传递不同属性类型的数组来搜索:

public static MethodInfo GetMethod(string methodName, Object _target)
    {
        try
        {
            MethodInfo info = _target.GetType().GetMethod(methodName);
            return info;
        }
        catch (AmbiguousMatchException ex)
        {
            MethodInfo info = _target.GetType().GetMethod(methodName, new System.Type[0]);
            if (info != null) return info;
            info = _target.GetType().GetMethod(methodName, new[] { typeof(int) });
            if (info != null) return info;
            info = _target.GetType().GetMethod(methodName, new[] { typeof(float) });
            if (info != null) return info;
            info = _target.GetType().GetMethod(methodName, new[] { typeof(double) });
            if (info != null) return info;
            info = _target.GetType().GetMethod(methodName, new[] { typeof(string) });
            if (info != null) return info;
            info = _target.GetType().GetMethod(methodName, new[] { typeof(bool) });
            return info;
        }
    }

这非常丑陋,但它适用于重载方法。但是,如果该方法具有可选参数,则它 returns NULL。我尝试使用 OptionalParamBinding 绑定标志,但即使对于没有重载和单个可选参数的方法,它也返回 NULL。

所以我的问题是: 我该怎么做?我需要这个静态方法来找到: - 使用 int、float、double、string 或 bool 参数重载方法 - 如果失败,则使用可选的 int、float、double、string 或 bool 参数重载 - 如果失败,不带任何参数的重载

对于您的特定要求,在 LINQ 查询中很容易做到这一点。

var validParameterTypes = new HashSet<Type> { typeof(int), typeof(float), ... };

var methods = from method in _target.GetType().GetMethods()
              let parameters = method.GetParameters()
              let hasParameters = parameters.Length > 0
              let firstParameter = hasParameters ? parameters[0] : null
              let isOptionalParameter = (hasParameters && firstParameter.IsOptional) ? true : false
              where method.Name == methodName &&
                    (!hasParameters || validParameterTypes.Contains(firstParameter.ParameterType))
              orderby parameters.Length descending, isOptionalParameter
              select method;

此时您评估查询中的方法,看看它们是否满足您的需求。

不过,还有一个不同的问题,那就是“我应该我这样做吗?”。 TyCobb 已经在他的评论中提到了这一点,他是对的。

您目前尝试做事的方式是大量的工作,没有立竿见影的效果。所以你得到了一个重载列表,这对你没有真正的帮助。现在你必须自己做重载解析并找到要调用的 "best" 重载(或者只取你找到的第一个重载,但如果方法是 added/removed/changed 就很容易中断)。

假设您还存储了您要查找的参数类型(如果有)。知道这会将您的代码压缩为:

var parameterTypes = (knownParameterType == null ) ? Type.EmptyTypes : new[] { knownParameterType };
var method = _target.GetType().GetMethod(methodName, parameterTypes);

更简单、更清晰、更明显正确!您甚至不必在此处检查允许的参数类型,让它们作为构建您正在定义的有效 "action type" 的一部分来执行此操作。