代码之家  ›  专栏  ›  技术社区  ›  Dave

针对案例a==b,专门实现genericType<a,b>

  •  0
  • Dave  · 技术社区  · 15 年前

    我有一个接受两个类型参数的泛型类, Generic<A, B> . 此类具有签名的方法非常长,并且 A B 明显不同。然而,如果 A == B 签名完全匹配,无法执行重载解决方案。是否可以以某种方式为这种情况指定方法的专业化?或者强制编译器任意选择一个匹配的重载?

    using System;
    
    namespace Test
    {
        class Generic<A, B>
        {
            public string Method(A a, B b)
            {
                return a.ToString() + b.ToString();
            }
    
            public string Method(B b, A a)
            {
                return b.ToString() + a.ToString();
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Generic<int, double> t1 = new Generic<int, double>();
                Console.WriteLine(t1.Method(1.23, 1));
    
                Generic<int, int> t2 = new Generic<int, int>();
    // Following line gives:
    //     The call is ambiguous between the following methods
    //     or properties: 'Test.Generic<A,B>.Method(A, B)' and
    //     'Test.Generic<A,B>.Method(B, A)'
                Console.WriteLine(t2.Method(1, 2));   
            }
        }
    }
    
    5 回复  |  直到 15 年前
        1
  •  3
  •   JaredPar    15 年前

    对于纯泛型定义,无法强制编译器选择重载。这两种方法无法区分胜利者。

    选择一个或另一个似乎是个好主意,但决策需要具有确定性。即使是像文件中第一个这样简单的东西也不真正可行,因为您必须考虑部分类。如果每个方法都在不同的文件中,编译器将如何选择第一个方法?

    不过,您可以做的是添加一个接受int的方法的非泛型版本。编译器将选择非泛型版本而不是泛型版本,它将在这个非常有限的场景中产生胜利。不过,对于每种可能有冲突的类型,您都必须重复这一点。

    例如。添加此方法可以解决编译错误,但只适用于int。

    public string Method(int b, int a)
    {
        return b.ToString() + a.ToString();
    }
    
        2
  •  2
  •   Dave    15 年前

    感谢您的回答,他们促使我进入这个解决方案:

    using System;
    
    namespace Test
    {
        class Generic<A, B>
        {
            public string Method(A a, B b)
            {
                return this.DefaultMethod(a, b);
            }
    
            protected string DefaultMethod(A a, B b)
            {
                return a.ToString() + b.ToString();
            }
    
            public string Method(B b, A a)
            {
                return b.ToString() + a.ToString();
            }
        }
    
        class Generic<A> : Generic<A, A>
        {
            public new string Method(A a, A b)
            {
                return base.DefaultMethod(a, b);
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                Generic<int, double> t1 = new Generic<int, double>();
                Console.WriteLine(t1.Method(1.23, 1));
    
                Generic<int> t2 = new Generic<int>();
                Console.WriteLine(t2.Method(1, 2));
            }
        }
    }
    
        3
  •  1
  •   Damovisa    15 年前

    我知道它有点破坏了泛型的目的,但是如果只定义一次方法,使用两个类型的参数,会怎么样呢? object ?

    在方法内部,您可以检查类型并计算出要调用的两个选项之一。

    namespace Test
    {
        class Generic<A, B>
        {
            public string Method(object a, object b)
            {
                if (a is A && b is B)
                    return MethodOneTwo;
                else if (a is B && b is A)
                    return MethodTwoOne;
                else
                    throw new ArgumentException("Invalid Types");
            }
    
            private string MethodOneTwo(A a, B b)
            {
                return a.ToString() + b.ToString();
            }
    
            private string MethodTwoOne(B b, A a)
            {
                return b.ToString() + a.ToString();
            }
        }
    }
    
        4
  •  0
  •   AaronLS    15 年前

    这将使用反射来获取方法并任意调用方法。通过对参数和返回类型进行过滤,您可以使这一点更为健壮,因为在获取方法时,这些参数和返回类型都是预期的。

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace ConsoleApplication1
    {
        using System;
        using System.Reflection;
    
        namespace Test
        {
            class Generic<A, B>
            {
                public string Method(A a, B b)
                {
                    return a.ToString() + b.ToString();
                }
    
                public string Method(B b, A a)
                {
                    return b.ToString() + a.ToString();
                }
            }
    
            class Program
            {
                static void Main(string[] args)
                {
                    Generic<int, double> t1 = new Generic<int, double>();
                    Console.WriteLine(t1.Method(1.23, 1));
    
                    Generic<int, int> t2 = new Generic<int, int>();
                    // Following line gives:
                    //     The call is ambiguous between the following methods
                    //     or properties: 'Test.Generic<A,B>.Method(A, B)' and
                    //     'Test.Generic<A,B>.Method(B, A)'
                   MethodInfo [] methods = t2.GetType().GetMethods();
                    foreach(MethodInfo method in methods)
                    {
                        if (method.Name == "Method")
                        {
                            method.Invoke(t2,new Object[2] {1,2});
                            break;
                        }
                    }
                }
            }
        }
    }
    

    编辑:这里有一个关于你面临的问题的博客,有一个类似于贾里德的解决方案。

    http://shiman.wordpress.com/2008/07/07/generic-method-overload-a-trap-for-c-net-library-developers/

    我们真正需要的是在预编译或编译时生成具体签名的模板。

        5
  •  -1
  •   shahkalpesh    15 年前

    不。

    如果您希望编译器任意地决定事情,那么您调用该方法的目的是什么?