2016-06-17 7 views
0

Nehmen wir an, ich habe eine abstrakte Basisklasse für Polymorphismus und ich möchte eine Methode schreiben, um einen abgeleiteten Typ in einen anderen zu konvertieren, aber ich kenne keinen der abgeleiteten Typen zum Zeitpunkt der Kompilierung . Ich glaube, Reflexion wäre der richtige Weg, um dies zu lösen, aber ich bin mir nicht sicher, was der richtige Weg wäre, um es zu implementieren. Hier bin ich gerade festgefahren.Konvertieren zwischen unbekannten Typen zur Laufzeit

Public Static BaseClass ConvertTo(BaseClass bc, Type type) { 
    //bc is currently DerivedClass1 which implements IConvertable 
    //type is currently DerivedClass2 
    //Trying to convert DerivedClass1 to DerivedClass2 
    return (BaseClass)ChangeType(bc, type); 
} 

Diese Methode wird DerivedClass1 zu DerivedClass2 konvertieren, aber ich hatte das IConvertable Schnittstelle für DerivedClass1 zur Umsetzung für sie zu arbeiten, die ich mit unglücklich bin, weil es mit 15 unnötigen Methoden kommt ich zu implementieren.

Gibt es einen eleganteren Weg, dies zu lösen, etwas, das näher an der Kompilierzeit Casting ist? Eine, bei der die Methode entweder erfolgreich sein oder eine Laufzeitausnahme auslösen würde, abhängig davon, ob DerivedClass1 einen Darstellungsklasse-2-Operator hatte. Etwas mehr wie:

Public Static BaseClass ConvertTo(BaseClass bc, Type type) { 
    //First down cast it to bc, then sideways cast it to type. 
    return (type)((bc.GetType())bc) 
} 
+0

Sie werden also die Arbeit in einer benutzerdefinierten Konvertierung ausführen, und Sie möchten das einfach finden und über Reflektion ausführen? –

+0

Sind Sie sicher, dass Sie nicht versuchen, Kopien ähnlicher Strukturen zu haben? Automapper könnte nützlicher sein, was auch immer es ist, versuchen Sie todo – Arjang

Antwort

3

Es klingt wie Sie nach Reflexion über benutzerdefinierte Konvertierungsoperatoren fragen. Sie können bei denen mit Reflexion durch öffentliche statische Methoden und Filterung auf diejenigen namens op_explicit oder op_implicit, mit den richtigen Parameter und Rückgabetypen und einschließlich MethodAttributes.SpecialName. Dann rufen Sie einfach die Methode als normal auf.

Hier einige Beispiel-Code, den ich schnell gepeitscht haben - Sie auch mehr Kontrollen für Robustheit hinzufügen möchten, sind Konvertierungen abgeleitete Typen oder von Basistypen, etc ..., aber es ist ein Anfang:

using System; 
using System.Linq; 
using System.Reflection; 

class Foo 
{ 
    public int Value { get; set; }   
    public static explicit operator Bar(Foo x) => new Bar { Value = x.Value }; 
    public static explicit operator Foo(Bar x) => new Foo { Value = x.Value }; 
} 

class Bar 
{ 
    public int Value { get; set; } 
} 

class Test 
{ 
    static void Main() 
    { 
     var foo = new Foo { Value = 10 }; 
     var bar = Convert<Bar>(foo); 
     Console.WriteLine(bar.Value); 
     foo = Convert<Foo>(bar); 
     Console.WriteLine(foo.Value);   
    } 

    public static T Convert<T>(object source) 
    { 
     var conversion = FindConversion(source.GetType(), typeof(T)); 
     if (conversion == null) 
     { 
      throw new InvalidOperationException("No conversion found"); 
     } 
     return (T) conversion.Invoke(null, new[] { source }); 
    } 

    private static MethodInfo FindConversion(Type fromType, Type toType) 
    { 
     var expectedParameterTypes = new[] { fromType }; 
     var methods = from type in new[] { fromType, toType } 
         from method in type.GetMethods(BindingFlags.Public | BindingFlags.Static) 
         where method.Name == "op_Explicit" || method.Name == "op_Implicit" 
         where (method.Attributes & MethodAttributes.SpecialName) != 0 
         where method.ReturnType == toType 
         where method.GetParameters() 
            .Select(p => p.ParameterType) 
            .SequenceEqual(expectedParameterTypes) 
         select method; 
     return methods.FirstOrDefault(); 
    } 
} 
+0

Vielen Dank! Das war genau das, wonach ich suchte. – Brian