2016-12-19 27 views
5

jestem generowania kodu, który trzeba sprawdzić równość użyciu SyntaxGeneratorJak dowiedzieć się, czy rodzaj obsługuje operator równości

Próbka:

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() }); 
    } 
    ... 

Problem jest to, że nie obsługuje typy takie jak int.

Guess szukam czegoś podobnego SupportsValueEquals(ITypeSymbol symbol)

Jak mogę dowiedzieć się, czy rodzaj wspiera równość poprzez ==?

+0

Już wyodrębniasz specjalne obudowy - po prostu specjalne przypadki innych wbudowanych typów, które mają wbudowane operatory równości? –

+2

Pamiętaj, że w każdym typie możesz mieć więcej niż jednego operatora ds. Równości. –

+0

To naprawdę bardzo dobre pytanie, ponieważ specyfikacja C# nie ma oczywistego pojęcia "równości wartości". Istnieje równość odniesienia i istnieje określona równość, ale nie obejmuje ona wszystkich pojęć "równości wartości". Na przykład, 'Struct.Byte' nie ma' op_Equals' i 'byte' nie ma predefiniowanego operatora równości, ale zastosowanie' == 'do' byte' działa tak czy inaczej, ponieważ jest niejawna promocja 'int', która * robi * ma predefiniowana równość. Zastanawiam się, dlaczego generator składni zawraca sobie głowę tym problemem. W jaki sposób proponuje wyróżniające smaki '==' (i dlaczego)? –

Odpowiedz

0

Jak sugeruje Skeet skończyło się specialcasing wszystkie rzeczy:

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

Proszę o komentarz jeśli zauważysz dumbs.

+1

Aktualnie zajmujesz się tylko typami z * dokładnie jednym * '==' przeciążeniem. Co jeśli jest wiele? –

+0

@JonSkeet Dzięki! Zostałem wspomniany w komentarzach, ale udało mi się go zgłupić. –

+0

Trzy ostatnie przypadki 'IntPtr',' UIntPtr' i 'DateTime' są błędne pod względem technicznym, jeśli chodzi o C#. Specyfikacja języka C# nie zna operatora '= == 'dla żadnego z nich. W każdym przypadku kompilator C# szuka zamiast tego operatora zdefiniowanego przez użytkownika i znajduje go. Tak więc należy je pominąć, podobnie jak pomija się "TimeSpan", "Guid" i inne nieokreślone typy. Ponadto, 'System.Enum' jest typem odniesienia, podobnie jak inne klasy, i nie powinno to być etykietą' case' w twojej sekcji przełącznika. –