【发布时间】:2019-10-16 02:34:54
【问题描述】:
我正在尝试自定义整数类型,遇到了一个有趣的问题,涉及泛型、隐式转换和 32 位整数。
以下是如何重现问题的精简示例。如果我有 两个 将 int 转换为 MyInt 的隐式方法,反之亦然,我会收到一个编译错误,看起来 C# 无法解析要使用的泛型类型。它只发生与int 或uint。所有其他整数类型都可以正常工作:sbyte,byte,short,ushort,long,ulong。
如果我删除其中一种隐式转换方法,它也可以正常工作。与循环隐式转换有关吗?
using Xunit;
public class MyInt
{
public int Value;
//If I remove either one of the implicit methods below, it all works fine.
public static implicit operator int(MyInt myInt)
{
return myInt.Value;
}
public static implicit operator MyInt(int i)
{
return new MyInt() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyInt myInt)
{
return this.Value == myInt.Value;
}
else
{
int other_int = (int)obj;
return Value == other_int;
}
}
}
下面是测试代码,显示了我在定义两个隐式方法时遇到的编译错误。
public class Test
{
[Fact]
public void EqualityTest()
{
MyInt myInt = new MyInt();
myInt.Value = 4 ;
Assert.Equal(4, myInt.Value); //Always OK which makes sense
//Compile errors when both implicit methods defined:
// Error CS1503 Argument 1: cannot convert from 'int' to 'string',
// Error CS1503 Argument 2: cannot convert from 'ImplicitConversion.MyInt' to 'string'
Assert.Equal(4, myInt);
}
}
我相信 C# 抱怨无法将这两种类型都转换为字符串,因为这是最后一个 Xunit.Assert.Equal() 重载的类型,而所有其他类型都无法匹配:
//Xunit.Assert.Equal methods:
public static void Equal<T>(T expected, T actual);
public static void Equal(double expected, double actual, int precision);
public static void Equal<T>(T expected, T actual, IEqualityComparer<T> comparer);
public static void Equal(decimal expected, decimal actual, int precision);
public static void Equal(DateTime expected, DateTime actual, TimeSpan precision);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer);
public static void Equal<T>(IEnumerable<T> expected, IEnumerable<T> actual);
public static void Equal(string expected, string actual, bool ignoreCase = false, bool ignoreLineEndingDifferences = false, bool ignoreWhiteSpaceDifferences = false);
public static void Equal(string expected, string actual);
我认为隐式转换没有出错,因为我可以让其他 similar examples 在与 32 位整数一起使用时产生相同的问题。
我正在一个 .NET Core 3.0 项目中进行测试。
任何帮助将不胜感激。谢谢!
说明:
我想知道的是为什么这只对 32 位整数失败。当类型是其他类型时,隐式转换正在工作(通过调试确认),如下例使用long。
using Xunit;
public class MyLong
{
public long Value;
public static implicit operator long(MyLong myInt)
{
return myInt.Value;
}
public static implicit operator MyLong(long i)
{
return new MyLong() { Value = i };
}
public override bool Equals(object obj)
{
if (obj is MyLong myInt)
{
return this.Value == myInt.Value;
}
else
{
long other_int = (long)obj;
return Value == other_int;
}
}
}
public class Test2
{
[Fact]
public void EqualityTest()
{
MyLong myLong = new MyLong();
myLong.Value = 4 ;
Assert.Equal(4, myLong); //NOTE! `4` is implicitly converted to a MyLong
//object for comparison. Confirmed with debugging.
}
}
【问题讨论】:
-
试试
Assert.Equal<int>(4, myInt);。我相信编译器在尝试推断泛型参数时不会考虑隐式运算符,因此会发现(string, string)是“最接近”的重载。 -
嗨@DStanley。
Assert.Equal<int>(4, myInt);确实有效,但并不理想。我在调试时确认编译器正在考虑隐式运算符。我在问题正文中添加了另一个示例,类型为long。在步骤Assert.Equal(4, myLong);,编译器将文字整数4转换为MyLong对象(通过调试确认)。为什么它会因 32 位整数而失败?
标签: c# generics implicit-conversion