2016-05-30 3 views
2

Wenn der betreffende Typ implementiert operator ==(), dann kann ich leicht einen Ausdruck erstellen, um es aufzurufen. Wenn der Operator jedoch in der Basisklasse definiert ist, funktioniert er nicht. Sehen Sie, wie drei Assertions bestehen, aber eine fehlschlägt.Wie erstelle ich einen Ausdruck, um einen Gleichheitsoperator aus einer Basisklasse aufzurufen?

Gibt es einen richtigen Weg, dies zu tun?

[TestClass] 
public class UnitTest1 
{ 
    [TestMethod] 
    public void TestMethod1() 
    { 
     Assert.IsTrue(new A(42) == new A(42)); // PASS 
     Assert.IsTrue(ExecuteOperatorEqual(new A(42), new A(42))); // PASS 
     Assert.IsTrue(new B(42) == new B(42)); // PASS 
     Assert.IsTrue(ExecuteOperatorEqual(new B(42), new B(42))); // FAIL 
    } 

    static bool ExecuteOperatorEqual<T>(T item1, T item2) 
    { 
     var expression = Expression.Lambda<Func<bool>>(
      Expression.Equal(
       Expression.Constant(item1), 
       Expression.Constant(item2))); 
     return expression.Compile()(); 
    } 
} 

class A 
{ 
    private readonly int _value; 

    public A(int value) 
    { 
     _value = value; 
    } 

    public static bool operator ==(A left, A right) => left._value == right._value; 

    public static bool operator !=(A left, A right) => left._value != right._value; 
} 

class B : A 
{ 
    public B(int value) : base(value) 
    { 
    } 
} 
+0

"es funktioniert nicht" - in welcher Weise scheitert es? – Blorgbeard

+0

Siehe die Kommentare im Code: Die ersten 3 Assertions passieren, aber die vierte nicht. –

+1

Hmm, ich denke [Expression.Equal] (https://msdn.microsoft.com/en-us/library/bb352749.aspx) schaut nicht auf die Oberklasse, wenn sie versucht, die Gleichheits-Methode zu finden. [Diese Überladung] (https://msdn.microsoft.com/en-us/library/bb352235.aspx) ermöglicht es Ihnen, ein MethodInfo zu spezifizieren. – Blorgbeard

Antwort

1

Ich bin mir nicht sicher, ob es sinnvoll, in Ihrem Kontext macht, aber Sie können dieses Problem beheben, um das Method Sie vorbei Expression.Equal

static bool ExecuteOperatorEqual<T>(T item1, T item2) 
    { 
     BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy; 
     var equalityMethod = typeof(T).GetMethod("op_Equality", bindingAttr, null, new Type[] { typeof(T), typeof(T) }, null); 

     var expression = Expression.Lambda<Func<bool>>(
      Expression.Equal(
       Expression.Constant(item1), 
       Expression.Constant(item2), 
       false, 
       equalityMethod 
       )); 
     return expression.Compile()(); 
    } 

I System.Core.dll und die Parameter Klasse hatte reflektiert haben nicht für jeden überladenen Operator suchen, wie Sie unten sehen können:

private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) 
    { 
     Type[] types = new Type[] 
     { 
      leftType, 
      rightType 
     }; 
     Type nonNullableType = leftType.GetNonNullableType(); 
     Type nonNullableType2 = rightType.GetNonNullableType(); 
     BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; 
     MethodInfo methodInfo = nonNullableType.GetMethodValidated(name, bindingAttr, null, types, null); 
     if (methodInfo == null && !TypeUtils.AreEquivalent(leftType, rightType)) 
     { 
      methodInfo = nonNullableType2.GetMethodValidated(name, bindingAttr, null, types, null); 
     } 
     if (Expression.IsLiftingConditionalLogicalOperator(leftType, rightType, methodInfo, binaryType)) 
     { 
      methodInfo = Expression.GetUserDefinedBinaryOperator(binaryType, nonNullableType, nonNullableType2, name); 
     } 
     return methodInfo; 
    } 

die BindingFlags.FlattenHierarchy Hinzufügen finden würde th e Gleichheitsoperator. Sie müssen einen Grund haben, dies nicht zu der .Net hinzuzufügen.

+0

Danke. Leider weiß ich in meinem Kontext nicht, welcher Typ den Gleichheitsoperator implementiert. –

+1

Ich habe gerade einen Code hinzugefügt, um die Gleichheits-Methode aus der Basisklasse zu finden. Hoffe es kann dir helfen. –

+1

Ich denke, Sie brauchen nicht die Zeile 'var gleich = typeof (B). GetMethod (" op_Equality ");'. Außerdem würde ich Binding-Flags verwenden, da Operatoren öffentlich und statisch sein müssen: 'BindingFlags.Static | BindingFlags.Public' –

Verwandte Themen