C# 反射,获取重载方法

6

我已经查看了一些关于反射和重载方法的帖子,但没有找到任何有用的信息。我找到了一个帖子(链接),但没能得到太多帮助。

我有以下两个方法:

1 | public void Delete<T>(T obj) where T : class { ... }
2 | public void Delete<T>(ICollection<T> obj) where T : class { ... }

我正在尝试获取第一种方法。

我尝试了经典的GetMethod("Delete")方法,但由于有两个同名方法,所以抛出了Ambiguous异常。我尝试通过添加一个额外的参数来指定方法模式,例如GetMethod("Delete", new [] { typeof(Object) }),但没有找到任何东西(返回null)。

我想我可能只需循环遍历所有方法并检查参数。

我编写了以下方法...

    public static IEnumerable<MethodInfo> GetMethods(this Type type, String name, Type schemaExclude)
    {
        IEnumerable<MethodInfo> m = type.GetRuntimeMethods().Where(x => x.Name.Equals(name));
        return (from r in m let p = r.GetParameters() where !p.Any(o => schemaExclude.IsAssignableFrom(o.ParameterType)) select r).ToList();
    }

...该方法返回不包含参数类型为schemaExclude的方法。

我像这样调用它:GetMethods("Delete", typeof(ICollection)),但结果并不如预期。

显然,..ICollection'1[T] 不可分配给 ICollection。它也不可分配给 IEnumerableIEnumerable<>ICollection<>。我又尝试了 typeof(Object),这次可以正常工作,但是返回了所有方法(就像它应该做到的那样)。

我错过了什么?


2
当使用反射并请求具有特定类型参数的方法时,您不是在请求具有兼容类型的方法,而是在请求具有那些特定类型参数的方法。任何继承和接口实现都必须由您的代码处理。因此,您请求了一个带有ICollection参数的“Delete”方法,但没有找到这样的方法。 - Lasse V. Karlsen
@LasseV.Karlsen 感谢您的评论。是的,这就是我想到的。这就是为什么我在编写方法时采用了不同的方法,尝试检查应该被排除的类型是否从参数类型分配。这应该涵盖类的任何继承。您建议检查什么?对于不同的方法,有什么建议吗? - товіаѕ
1
你是否知道编译时的 T?那么,例如 GetMethods("Delete", typeof(ICollection<int>)) 就很简单了。否则,你需要在前面构建运行时类型,使用 Type.MakeGenericType - MakePeaceGreatAgain
@HimBromBeere 在编译时使用吗?不是的。我以非常通用的方式使用它来进行基于实体框架的数据操作。T 可以是我的领域中支持的任何模型。我处理的对象是一个代理对象,这意味着我被迫使用反射来访问具有适当泛型类型的方法。我可以尝试在运行时构建泛型类型以获取 ICollection<T>,但我不确定这是否与方法的模式匹配。让我试一下... - товіаѕ
@HimBromBeere 我尝试使用 typeof(ICollection<>).MakeGenericType(t),其中 t 等于 Entity Framework 模型类型。我的方法返回了两个方法作为结果,这意味着它与模式不匹配。 - товіаѕ
1个回答

4
您可以通过检查其泛型参数类型来查找方法,就像这样:
return type
    .GetRuntimeMethods()
    .Where(x => x.Name.Equals("Delete"))
    .Select(m => new {
         Method = m
    ,   Parameters = m.GetParameters()
    })
    .FirstOrDefault(p =>
        p.Parameters.Length == 1
    &&  p.Parameters[0].ParameterType.IsGenericType
    &&  p.Parameters[0].ParameterType.GetGenericTypeDefinition() == typeof(ICollection<>)
    )?.Method;

以上过滤方法符合以下条件:

  • 被称为“Delete”,
  • 只有一个参数,
  • 参数是一个通用类型,
  • 通用参数类型由ICollection<>构造

演示。


谢谢您的答复!那确实解决了我的问题,虽然我真正需要的只是您演示中的“ParameterType.IsGenericType”部分。我将我的检查更改为schemaExclude.IsAssignableFrom(o.ParameterType.IsGenericType ? o.ParameterType.GetGenericTypeDefinition() : o.ParameterType)。这就做到了。 - товіаѕ

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