2016-06-17 3 views
0

Допустим, у меня есть абстрактный базовый класс, используемый для полиморфизма, и мне нравится писать метод для преобразования одного производного типа в другой, но я не знаю ни одного из производных типов во время компиляции , Я считаю, что рефлексией будет правильный путь для решения этой проблемы, но я не уверен, каким правильным способом ее реализовать. Вот где я сейчас застрял.Преобразование между неконструированными производными типами во время выполнения

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

Этот метод преобразует DerivedClass1 в DerivedClass2, но я должен был Реализовать IConvertable интерфейс для DerivedClass1 для того, чтобы работать, что я недоволен, потому что речь идет о 15 ненужных методов, которые я должен реализовать.

Есть ли более элегантный способ решить эту проблему, что ближе к компиляции времени? Тот, в котором метод либо преуспел, либо выбросил исключение времени выполнения в зависимости от того, был ли DerivedClass1 включен Оператором Cast DeringsClass2. Что-то еще:

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

Итак, вы собираетесь выполнять работу в пользовательском преобразовании, и вы просто хотите найти это и выполнить его с помощью отражения? –

+0

Вы уверены, что не пытаетесь копировать подобные структуры? Automapper может быть более полезным, что бы вы ни пытались сделать – Arjang

ответ

3

Похоже, вы просите о рефлексии над пользовательскими операторами преобразования. Вы можете обратиться к тем, у кого есть отражение, попросив публичные статические методы и фильтрацию к тем, которые называются op_explicit или op_implicit, с правильными параметрами и типами возврата, включая MethodAttributes.SpecialName. Затем просто вызовите метод как обычно.

Вот некоторые примеры кода я взбитый быстро - вы хорошо можете добавить дополнительные проверки для надежности, включает преобразование в производные типы или из базовых типов, и т.д. ... но это только начало:

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

Спасибо! Это именно то, что я искал. – Brian

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