2011-03-07 13 views
4

文字列をそれぞれの型に変換する一連の値型変換器があります。私は必要に応じて、タイプに基づいてこれらのコンバータを作成する責任がある工場を持っています。私は工場とコンバーターを汎用的に保つために努力していますが、私はいくつかの問題を抱えています。私は工場で.Createメソッドを呼び出すまで型を知らないので、その型を引数として渡せるようにする必要があります。問題は、私の.CreateメソッドがValueConverter<int>のようなより適切な値コンバータの代わりにValueConverter<Type>を探していると思うということです。私は何かを逃している、あるいはおそらくそれを完全に間違っている。ここで 汎用クラスを作成する汎用ファクトリ

は私のコンバータのカップルやインタフェースです:

public class ValueConverterFactory : IValueConverterFactory 
{ 
    private readonly IUnityContainer _container; 

    public ValueConverterFactory(IUnityContainer container) 
    { 
     _container = container; 
    } 

    public IValueConverter<T> Create<T>(T type) 
    { 
     return _container.Resolve<IValueConverter<T>>(); 
    } 
} 

と団結はこのようなものを設定されています:

Container.RegisterType<IValueConverter<int>, IntValueConverter>(); 
Container.RegisterType<IValueConverter<DateTime>, DateTimeValueConverter>(); 
その後

public interface IValueConverter<T> 
{ 
    T Convert(object objectToConvert); 
} 

public class IntValueConverter : IValueConverter<int> 
{ 
    public int Convert(object objectToConvert) 
    { 
     return System.Convert.ToInt32(objectToConvert); 
    } 
} 

public class DateTimeValueConverter : IValueConverter<DateTime> 
{ 
    public DateTime Convert(object objectToConvert) 
    { 
     return System.Convert.ToDateTime(objectToConvert); 
    } 
} 

、私はこのような工場を持っています

私はこのように工場に電話する必要があります:

var objectType = someObj.GetType(); 
var valueConverter = _valueConverterFactory.Create(objectType); 
+0

どのようにCreateメソッドを呼び出すのですか?問題はIoCのものかもしれません。私はそれを一度も使用しておらず、言い訳もできません。しかし、単純な工場では、次のことができます:IConverter myConverter = factory.Create (typeof(int)); – Sisyphus

+0

実行時まで型がわからないため、型を汎用メソッド呼び出しで指定できません。 –

+0

あなたがしようとしていることを実行できるかどうかは分かりません。あなたは、ランタイムまで型を知らないと言っています。しかし、Convertを使用するには、int myVar = Convert ...と言う必要がありますか、多分var myVar = Convertをしようとしていますか?私は暗黙の型を使用することに精通していないので、読みやすさやその他の側面(私はLINQではなくnhibを使用しています)のために暗黙の型定義のファンではありませんが、コンパイラは何とか型を決定できる必要があります。あなたは完全にタイピングするのを避けるためにそれを使うことはできません。コンパイラが意図した実装から型を推論する方法がわかりません。 – Sisyphus

答えて

0

それはあなたが求めて何だ場合、私は知らないが、私はRhinoのイグルーの枠組みの中で、このエレガントで短いコードを見つけました:ConversionUtil.cs - それは、任意の型に文字列を変換し...

public static object ConvertTo(Type type, string inject) 
    { 
     if (inject == null) 
     { 
      return type.IsValueType ? Activator.CreateInstance(type) : null; 
     } 

     if (type.IsInstanceOfType(inject)) 
     { 
      return inject; 
     } 
     else if (type == typeof(int)) 
     { 
      int temp; 
      if (int.TryParse(inject, out temp)) 
       return temp; 
      return null; 
     } 
     else if (typeof(IConvertible).IsAssignableFrom(type)) 
     { 
      return Convert.ChangeType(inject, type); 
     } 

     //Maybe we have a constructor that accept the type? 
     ConstructorInfo ctor = type.GetConstructor(new Type[] { inject.GetType() }); 
     if (ctor != null) 
     { 
      return Activator.CreateInstance(type, inject); 
     } 

     //Maybe we have a Parse method ?? 
     MethodInfo parseMethod = type.GetMethod("Parse", BindingFlags.Static | BindingFlags.Public); 
     if (parseMethod != null) 
     { 
      return parseMethod.Invoke(null, new object[] { inject }); 
     } 

     throw new ArgumentException(string.Format(
      "Cannot convert value '{0}' of type '{1}' to request type '{2}'", 
      inject, 
      inject.GetType(), 
      type)); 
    } 
+0

本当にありません。これはオブジェクトを返すので、オブジェクトが変換された後で実際にキャストするのを避けたいのです。私はカプセル化を破ることなく後でコンバーターを追加できるようにしたい。しかし、これを送信していただきありがとうございます。たぶんそれは誰かを助けるでしょう。 –

+0

@Byron Sommardahl - それでは騒いでよ... –

0

をおそらく次のようなものでしょう:

public IValueConverter<T> Create<T>(T type) 
{ 
    return _container.Resolve(typeof(IValueConverter<>).MakeGenericType(type.GetType())); 
} 

私はそれをテストしていませんが、

+1

それはうまくいくかもしれません!解決の仕方によって異なりますが、私はこれが正しいタイプになると信じています。しかし、 'T'の代わりに' type'を渡すべきです。そして、私は 'T型'が '型型'を意図していると仮定しています。 –

+0

問題は、彼がコンパイル時に 'T'を知らないので、何か具体的な' T'(彼がそれを知らないので)のために 'Create 'を呼び出すことができず、コンパイラはそれを推論できません'type'は' Type'のインスタンスであるため、 'Create(type) 'から削除します。コンパイル時に 'T 'を知らなくても、強いタイピングができないという根本的な問題です。 – jason

+0

よく分かりませんが、Reflectionを使用してCreateを呼び出すと何が問題になりますか? – driushkin

0

全く異なるノートでは、とにかくカバーの下で変換を呼び出すのであれば、System.Convert.ChangeType(Object, Type)を使用しないのはなぜですか?

カスタムタイプのサポートを追加する必要がある場合は、独自のタイプコンバータを作成し、TypeConverterAttributeで登録することができます。

1

トラブルはその後、私の.Create方法は、私はValueConverter<int>ような、より適切な値コンバータの代わりにValueConverter<Type>を探しています考えて、ということです。

まず、なぜこれが起こっているのかを理解する必要があります。あなたは私たちに呼び出し元のコードを与えなかったが、それはおそらく、このようなものになります。

Type type = SomehowResolveTheTypeThatINeedToConvertTo(); 
factory.Create(type); 

右が

は、それが一般的な方法を呼び出すために起こっているの Typeがタイプに代入さ

IValueConverter<T> ValueConverterFactory.Create<T>(T type) 
パラメータ T

第2に、基本的に何をしようとしているのかを理解する必要があります。コンパイル時に型がわからないので、強い型付けをすることはできません。強いタイプのIValueConverter<T>を取得するには、Tが何であるかを知る必要があります。あなたは、コンバーターがTの代わりにobjectを返すことを受け入れることを喜んで受け入れるか、またはコンパイル時にタイプTを知る方法を見つけてください。

0

これは通常、ドリームスキンが溶けていないのと同じように行われます。オープンジェネリックタイプをコンテナに登録する必要があります。 StructureMapを使用すると、これはこのようなものになるだろう:

builder.RegisterGeneric(typeof(IValueConverter<>)); 

あなたはその後、解決するには、ジェネリック型を構築します::

Type openType = typeof(IValueConverter<>); 
Type closedType = openType.MakeGenericType(type); 
var instance = container.Resolve(closedType); 
Autofacで

Scan(scanner => 
{ 
    scanner.TheCallingAssembly();  
    scanner.ConnectImplementationsToTypesClosing(typeof (IValueConverter<>)); 
}); 

、それはこのようなものになるだろう

私はファクトリメソッドのパラメータを一般的にしたいとは思わない。

public IValueConverter<T> Create<T>(Type type) 
{ 
    // ... 
} 

このすべてを作成するのではなく、Automapperだけを使用するのはなぜですか?ここで私は、一般的に作成するマッピングの種類があります:

public class DateTimeToDateMapping : IAutoMapperInitializer 
{ 
    public void Initialize(IConfiguration configuration) 
    { 
     configuration.CreateMap<DateTime, Date>().ConstructUsing(
      dateTime => new Date(dateTime.Year, dateTime.Month, dateTime.Day)); 
    } 
} 

ここでは、このマッピングを使用することができる方法は次のとおりです。

var date = _mappingEngine.Map<DateTime, Date>(DateTime.Today); 

私はあまりSystem.Convertを使用していたことを知りませんが、それはdoesnの私はそれが意図的なものであると思われるので、特定のものから変換する方法しか知りません。 Automapperを使用する場合は、マッピングを簡単にテストすることもできます。

関連する問題