我有一个泛型类,它带有两个类型参数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));
}
}
}
答案 0 :(得分:3)
鉴于纯粹的通用定义,没有办法强制编译器选择重载。它无法区分两种方法之间的胜利者。
选择一个或另一个似乎是一个好主意,但决策需要是确定性的。即使是文件中第一个简单的东西也不是真的可行,因为你必须考虑部分类。如果每个方法都在不同的文件中,编译器将如何选择第一种方法?
您可以做的是添加接受int的方法的非泛型版本。编译器将选择非通用版本而不是通用版本,并且在这种非常有限的情况下它将产生胜利。对于可能存在冲突的每种类型,您都必须重复这一点。
例如。添加此方法将解决编译错误,但仅适用于int。
public string Method(int b, int a)
{
return b.ToString() + a.ToString();
}
答案 1 :(得分: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));
}
}
}
答案 2 :(得分: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();
}
}
}
答案 3 :(得分: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/
我们真正需要的是在预编译或编译时生成具体签名的模板。
答案 4 :(得分:-1)
没有
如果您希望编译器任意决定事情,那么调用该方法的目的是什么?