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节第二段)。不管它是否转换为实现相等运算符的类型,这些运算符都不是候选运算符。