Мой конвертер универсального типа плохо пахнет, исключения во время выполнения, объект как поймать все, бокс и т. Д. - PullRequest
2 голосов
/ 27 октября 2010

Во-первых, Я задал этот вопрос в другом месте , но meta.stackoverflow.com, похоже, считает, что задавать те же вопросы в другом месте - это хорошо , так что здесь все. Я обновлю оба, если получу ответ.

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

var converter = GetMySingletonConverterRegistryPlease();
var somePoint = GetMeSomePointFromSomewhereThanks();

converter.Register<Point, List<int>>( 
  point => new List<int>{ point.X, point.Y } 
); 

var someInts = somePoint.To<List<int>>();

Итак, я придумал следующее. Что меня совсем не устраивает и хотелось бы получить несколько советов (я перечислю, почему мне это не нравится после фрагмента кода)

public sealed class TypeConverterRegistry : TypeConverterRegistryBase {
  public static readonly TypeConverterRegistry Instance = new 
    TypeConverterRegistry();
  static TypeConverterRegistry() {}
  TypeConverterRegistry() {}
}

public abstract class TypeConverterRegistryBase {
  private readonly Dictionary<object, Delegate> _converters = new 
    Dictionary<object, Delegate>();

  public void Register<TFrom, TTo>( Func<TFrom, TTo> converter ) {
    var key = new { From = typeof( TFrom ), To = typeof( TTo ) };
    _converters[ key ] = converter;
  }

  public TTo ConvertTo<TTo>( object from ) {
    var key = new { From = from.GetType(), To = typeof( TTo ) };

    if( !_converters.ContainsKey( key ) ) 
      throw new KeyNotFoundException( 
        "No converter has been registered that takes a " + key.From + 
        " and returns a " + key.To );

    var converter = _converters[ key ];
    return (TTo) converter.DynamicInvoke( from );
  }
}

public static class Extensions {
  public static TTo To<TTo>( this object value ) {
    return TypeConverterRegistry.Instance.ConvertTo<TTo>( value );
  }
}  

Мне не нравится то, что я здесь сделал, потому что он не является строго типизированным / ограниченным, его легко случайно использовать неправильно и получить исключение времени выполнения, я использую объект как перехват всех, и у меня также есть плохое предчувствие того, как я звоню в DynamicInvoke и проверяю результат. Вы, ребята, без сомнения, увидите еще больше проблем, чем это! Также я чувствую себя плохо из-за создания метода расширения для объекта.

То, что я делаю , похоже на полученный синтаксис!

Так что я очень ценю любой совет, даже если это всего лишь толчок в правильном направлении.

Или заверение, что это не такой уж плохой способ сделать это: P

1 Ответ

4 голосов
/ 27 октября 2010

Взгляните на AutoMapper (http://automapper.codeplex.com/). Несмотря на различие в намерениях, ваш проект разделяет много общего, и вы можете многое узнать из их шаблонов и кода.

С точки зрения исключений времени выполнения, это может сводиться к юнит-тестированию, поскольку вы полагаетесь на то, что пользователь регистрирует тип перед его использованием. Этого нельзя избежать, и AutoMapper делает то же самое, но там тоже есть кое-что для тестирования.

Я бы настоятельно рекомендовал переписать метод ConvertTo , чтобы он был универсальным, чтобы параметр from был универсальным вместо типа object . Вы можете сделать это что-то вроде:

  public TTo ConvertTo<TFrom, TTo>( TFrom from ) {
    var key = new { From = typeof( TFrom ) To = typeof( TTo ) };

    if( !_converters.ContainsKey( key ) ) 
      throw new KeyNotFoundException( 
        "No converter has been registered that takes a " + key.From + 
        " and returns a " + key.To );

    var converter = _converters[ key ] as Func<TFrom, TTo>;
    return converter(from);
  }

это также решит вашу проблему с помощью метода расширения. Теперь вы вызываете с помощью:

public static TTo Convert<TFrom, TTo>(this TFrom value){
return TypeConverterRegistry.Instance.Convert<TFrom, TTo>(value);
}
...