0

我有一个泛型类,它接受两个类型参数,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));   
        }
    }
}
4

5 回答 5

3

鉴于纯泛型定义,无法强制编译器选择重载。它无法区分这两种方法的赢家。

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

您可以做的是添加接受 int 的方法的非泛型版本。编译器将选择非通用版本而不是通用版本,并且它将在这种非常有限的情况下产生胜利。但是,您必须对可能存在冲突的每种类型重复此操作。

例如。添加此方法将解决您的编译错误,但仅适用于 int。

public string Method(int b, int a)
{
    return b.ToString() + a.ToString();
}
于 2009-04-03T03:31:12.610 回答
2

感谢您提供好的答案,他们促使我采用了这个解决方案:

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));
        }
    }
}
于 2009-04-03T04:44:02.453 回答
1

我知道这有点违背泛型的目的,但是定义一次方法,采用两个类型的参数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();
        }
    }
}
于 2009-04-03T03:49:29.917 回答
0

这将使用反射来获取方法并任意调用一个。您可以通过过滤获取方法时预期的参数和返回类型来使其更加健壮。

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;
                    }
                }
            }
        }
    }
}

编辑:这是一个关于您面临的问题的博客,其解决方案类似于 Jared 的。

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

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

于 2009-04-03T03:54:31.807 回答
-1

不。

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

于 2009-04-03T03:31:00.817 回答