2016-12-19 2 views
5

Я генерации кода, который необходимо проверить равенство с помощью 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.

Guess Я ищу что-то вроде SupportsValueEquals(ITypeSymbol symbol)

Как я могу понять, если тип поддерживает равенство через ==?

+0

Вы уже являетесь специальными перегородками - только в особых случаях используются другие встроенные типы, которые имеют встроенные операторы равенства? –

+2

Остерегайтесь того, что вы можете иметь более одного оператора равенства в любом типе. –

+0

Это на самом деле очень хороший вопрос, потому что спецификация C# не имеет очень очевидного понятия о «равенстве ценности». Существует ссылочное равенство, и существует предопределенное равенство, но это не охватывает все понятия «равенства ценности». Например, 'Struct.Byte' не имеет' op_Equals' и 'byte' не имеет предопределенного оператора равенства, но применение' == 'to' byte' работает так или иначе, потому что есть неявное продвижение в 'int', которое * делает * предопределенное равенство. Интересно, почему генератор синтаксиса беспокоится об этом в первую очередь. Как он предлагает различать ароматы '==' (и почему)? –

ответ

0

Как предложили тарелочки я в конечном итоге specialcasing всех вещей:

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

Пожалуйста, комментарий, если вы заметили dumbs.

+1

В настоящее время вы обрабатываете типы только с * точно одной * '==' перегрузкой. Что делать, если их несколько? –

+0

@JonSkeet Спасибо! Был упомянут в комментариях, но мне это удалось ошеломить. –

+0

Последние три случая 'IntPtr',' UIntPtr' и 'DateTime' являются технически неправильными, когда речь идет о C#. Спецификация языка C# не знает о 'operator ==' для любого из них. В каждом случае компилятор C# ищет вместо него пользовательский оператор и находит его. Поэтому они должны быть опущены, так же как «TimeSpan», «Guid» и другие не предопределенные типы опущены. Кроме того, 'System.Enum' является ссылочным типом, как и другие классы, и он не должен быть ярлыком' case' в разделе вашего коммутатора. –

Смежные вопросы