简体   繁体   English

Type.GetMethod() 用于多态方法(泛型和非泛型)

[英]Type.GetMethod() for polymorphic method (both generic and non-generic)

I am currently creating a custom way of deep-copying my objects.我目前正在创建一种自定义方式来深度复制我的对象。 I use a static class for this functionality.我使用 static class 来实现此功能。

public static class CopyServer
{

    public static int CopyDeep(int original)
    {
        return original;
    }
    //not shown: same for all other value types I use (long, float,...)


    public static T CopyDeep<T>(T original) where T: ICopyAble
    {
        if (original == null)
            return default;
        if (original is ICopyAutofields)
            return CopyAutofields(original);
        return (T)original.CopyDeep();
    }

    private static T CopyAutofields<T>(T original)
    {
        Delegate del;
        if (!_copyFunctions.TryGetValue(typeof(T), out del))
        {
            //not shown: Building expression for parameter etc.
            foreach (var fieldInfo in typeof(T).GetFields())
            {
                //not shown: checking options set by custom attributes

                MethodInfo methodInfo = typeof(CopyServer).GetMethod("CopyDeep", new[] { fieldInfo.FieldType });
                //I can't remove the second param without getting an AmbiguousMatchException

                if (methodInfo == null)
                {
                    throw new Exception($"CopyDeep not defined for type {fieldInfo.FieldType}");
                }

                if (methodInfo.IsGenericMethod)
                    methodInfo = methodInfo.MakeGenericMethod(fieldInfo.FieldType);

                Expression call = Expression.Call(methodInfo, readValue);

                //not shown: Assign Expression

            }

            //not shown: return Expression and compiling
        }
        return ((Func<T, T>)del)(original);
    }
}

I use T CopyAutofields<T> to build functions (by building and compiling Expression Trees) so I don't have to create copy-functions for each and every class I want to copy by hand.我使用T CopyAutofields<T>来构建函数(通过构建和编译表达式树),因此我不必为要手动复制的每个 class 创建复制函数。 I control the copy-behaviour with Custom Attributes (I left this part in the code above since it is not relevant for my problem).我使用自定义属性控制复制行为(我将这部分留在上面的代码中,因为它与我的问题无关)。

The code works fine as long as long as only fields with types for which a non-generic function exists are used.只要仅使用存在非泛型 function 类型的字段,该代码就可以正常工作。 But it is not able to retrieve my generic function T CopyDeep<T> .但它无法检索我的通用 function T CopyDeep<T>

Example:例子:

//This works:
public class Manager : ICopyAble,ICopyAutofields
{
    public string FirstName;
    public string LastName;
}

//This doesn't
//Meaning: typeof(CopyServer).GetMethod("copyDeep", new[] { fieldInfo.FieldType }); 
//in T copyAutofields<T> returns null for the Manager-field and my exception gets thrown
public class Employee : ICopyAble,ICopyAutofields
{
    public string FirstName;
    public string LastName;
    public Manager Manager;
}

//This is what I was using before I started using the ICopyAutofields. 
//This approach works, but its' too much too write since my classes usually 
//have way more than three fields and I occasionally forget to update 
//copyDeep()-function if I add new ones.
public class Employee : ICopyAble,ICopyAutofields
{
    public string FirstName;
    public string LastName;
    public Manager Manager;

    public IModable CopyDeep()
    {
        var result = new Employee();
        result.FirstName = CopyServer.copyDeep(FirstName);
        result.LastName= CopyServer.copyDeep(LastName);
        result.Manager= CopyServer.copyDeep(Manager);
        return result;
    }
}

Long story short: I need a way of getting a matching function for a type T if both generic and non-generic functions with the right name exist.长话短说:如果具有正确名称的泛型和非泛型函数都存在,我需要一种为类型 T 获取匹配的 function 的方法。

In .NET 4.7.1 you need to use method GetMethods and filter the results:在 .NET 4.7.1 中,您需要使用方法GetMethods并过滤结果:

class MyClass
{
    public T M<T>(T t) { return default(T); }
    public int M(int t) { return 0; }
}

var m = typeof(MyClass).GetMethod("M", new[] { typeof(string) }); // null
var m1 = typeof(MyClass).GetMethods()
    .Where(mi => mi.Name == "M" && mi.GetGenericArguments().Any())
    .First(); // returns generic method

In .NET Standard 2.1 (and .NET Core since 2.1) there is another way to resolve generic type arguments - Type.MakeGenericMethodParameter , like you can see it in this answer .在 .NET 标准 2.1(和 .NET 核心自 2.1 起)中,还有另一种解决泛型类型 arguments - Type.MakeGenericMethodParameter的方法,就像您在此答案中看到的那样。

Also as workaround you can move your copyAutofields<T> method to generic class like CopyAutoFieldServer<T> :作为解决方法,您可以将copyAutofields<T>方法移动到通用 class ,例如CopyAutoFieldServer<T>

public static class CopyAutoFieldServer<T>
{
    public static T copyAutofields(T original) { ... }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM