C# 如何确定类型是否支持相等运算符
我正在生成需要使用C# 如何确定类型是否支持相等运算符,c#,roslyn,C#,Roslyn,我正在生成需要使用SyntaxGenerator 样本: if (property.Type.IsValueType || property.Type == KnownSymbol.String) { if (property.Type.TypeKind == TypeKind.Enum || property.Type.GetMembers("op_Equality").Length == 1) { var valueEqualsExpressi
SyntaxGenerator
样本:
if (property.Type.IsValueType || property.Type == KnownSymbol.String)
{
if (property.Type.TypeKind == TypeKind.Enum ||
property.Type.GetMembers("op_Equality").Length == 1)
{
var valueEqualsExpression = syntaxGenerator.ValueEqualsExpression(
SyntaxFactory.ParseName("value"),
SyntaxFactory.ParseExpression(fieldAccess));
return (IfStatementSyntax)syntaxGenerator.IfStatement(valueEqualsExpression, new[] { SyntaxFactory.ReturnStatement() });
}
...
问题是它不能处理诸如int
之类的类型
我想我正在寻找类似于SupportsValueEquals(itypesymb-symbol)
我如何通过
==
判断一个类型是否支持相等?正如Skeet所建议的那样,我最后特别列举了所有内容:
private static bool HasEqualityOperator(ITypeSymbol type)
{
switch (type.SpecialType)
{
case SpecialType.System_Enum:
case SpecialType.System_Boolean:
case SpecialType.System_Char:
case SpecialType.System_SByte:
case SpecialType.System_Byte:
case SpecialType.System_Int16:
case SpecialType.System_UInt16:
case SpecialType.System_Int32:
case SpecialType.System_UInt32:
case SpecialType.System_Int64:
case SpecialType.System_UInt64:
case SpecialType.System_Decimal:
case SpecialType.System_Single:
case SpecialType.System_Double:
case SpecialType.System_String:
case SpecialType.System_IntPtr:
case SpecialType.System_UIntPtr:
case SpecialType.System_DateTime:
return true;
}
if (type.TypeKind == TypeKind.Enum)
{
return true;
}
foreach (var op in type.GetMembers("op_Equality"))
{
var opMethod = op as IMethodSymbol;
if (opMethod?.Parameters.Length == 2 &&
type.Equals(opMethod.Parameters[0].Type) &&
type.Equals(opMethod.Parameters[1].Type))
{
return true;
}
}
return false;
}
如果你发现了哑巴,请发表评论。你已经是特殊的大小写枚举了——只是其他内置了相等运算符的内置类型的特殊情况而已?请注意,任何类型中都可以有多个相等运算符。这实际上是一个很好的问题,因为C#规范没有非常明显的“值相等”概念。有参考等式,也有预定义的等式,但这并不包括“值等式”的所有概念。例如,
Struct.Byte
没有op_Equals
,Byte
没有预定义的相等运算符,但是将=
应用到Byte
仍然有效,因为有一个隐式提升到int
,它确实具有预定义的相等性。我想知道为什么语法生成器首先要处理这个问题。它是如何提出区分==
(以及为什么)?@jeroemostert。这也可能发生在您自己的struct ColoredInt32
上,它没有操作符==
重载,而是有一个隐式操作符int
,这使得像oneColoredInt32==另一个ColoredInt32
这样的表达式合法。@JeppeStigNielsen:我正要发布它。:-)在封面下,C#和VB语法生成器甚至为valueequalexpression
和referenceequalexpression
生成相同的表达式。也许这种区别是针对那些确实存在语法差异的语言,但在这种情况下,你只需要知道你的目标语言是什么,就可以知道生成什么。因此,如果API实际上没有在某个地方提供SupportsValueEquals
,我会说这是API中的一个缺陷。您当前只处理只有一个=
重载的类型。如果有多个呢?@JonSkeet谢谢!在评论中提到了,但我设法使它哑口无言。最后三种情况IntPtr
,UIntPtr
,和DateTime
在C#方面在技术上是错误的。C语言规范不知道它们中任何一个的操作符==
。在每种情况下,C#编译器都会搜索用户定义的运算符,并找到一个。因此,应该省略这些类型,就像省略TimeSpan
、Guid
和其他非预定义类型一样。另外,System.Enum
是一个引用类型,就像其他类一样,它不应该是开关部分上的case
标签。啊,实际上,使用预定义的相等运算符(比如bool
和string
隐式转换为任何类型,但奇怪的是,它不是Enum类型,这在我看来像个bug);数字转换处理的类型有byte
@JeppeStigNielsen:实际上,我在做同样的事情,因为标准实际上解释了为什么这对枚举不起作用(第7.3.4节,第二段,最后一句话),但同样的一句话,它不应该对代理起作用,而且它确实起作用!我可以解释为什么它不适用于其他类型,如Exception
或Uri
,但是:如果结构本身没有定义相等运算符,则只考虑预定义的相等运算符(第7.3.4节第二段)。不管它是否转换为实现相等运算符的类型,这些运算符都不是候选运算符。