2013-07-24 2 views
5

をインスタンス化するために選択するために、列挙型を使用します。私はDTOのに関連付けしようとしている列挙型を持つクラス

public enum DtoSelection 
{ 
    dto1, 
    dto2, 
    dto3, 
} 

この列挙では108と値があります。

私はこれらのDTO年代ごとに、DTOオブジェクトを持っている:

public class dto1 : AbstractDto 
{ 
     public int Id { get; set; } 
     //some stuff specific to this dto 
} 

私は私のDTOに関連したタイプの新しいDTOオブジェクトを返します方法(最終的にサービスを)作るしようとしています

private AbstractDto(int id) 
{ 
     if (id == DtoSelection.Dto1.ToInt()) //extension method I wrote for enums 
      return new Dto1(); 
     if (id == DtoSelection.Dto2.ToInt()) 
      return new Dto2(); 
} 

明らかに私はこれを108回したくありません。何らかの理由で私の脳は明らかな何かを欠いているだけです。これを処理する最良の方法は何ですか?

+0

これが可能であれば私は不思議です – Jonesopolis

+0

まず、 'switch'を使って' if'リストを改善することができます。あなたはリフレクションを使いたいですか? –

+1

列挙型に108の異なるdtoオブジェクトを持つ理由は何ですか?なぜ配列を使用しないのですか? – chancea

答えて

3

このクラスは、あなたがやりたいだろうDtoクラスがAbstractDtoと同じ名前空間で定義されている限り、そうでなければそれを微調整する必要があります:

は、次の列挙型とクラスを考える:

public enum DtoSelection 
{ 
    Dto1, 
    Dto2, 
    Dto3, 
} 

public abstract class AbstractDto 
{ 
} 

public class Dto1 : AbstractDto 
{ 
} 

public class Dto2 : AbstractDto 
{ 
} 

public class Dto3 : AbstractDto 
{ 
} 

この方法は、それらを解決します:

public static class DtoFactory 
{ 
    public static AbstractDto Create(DtoSelection dtoSelection) 
    { 
     var type = Type.GetType(typeof(AbstractDto).Namespace + "." + dtoSelection.ToString(), throwOnError: false); 

     if (type == null) 
     { 
      throw new InvalidOperationException(dtoSelection.ToString() + " is not a known dto type"); 
     } 

     if (!typeof(AbstractDto).IsAssignableFrom(type)) 
     { 
      throw new InvalidOperationException(type.Name + " does not inherit from AbstractDto"); 
     } 

     return (AbstractDto)Activator.CreateInstance(type); 
    } 
} 
4

Activator.CreateInstanceメソッドを使用し、列挙型のToString値を渡します。

Type type = Type.GetType(DtoSelection.dto1.ToString()); 
var temp = Activator.CreateInstance(type); 
+0

私はこれが好きです。私は各dtoのためにこれを108回しなければならないでしょう。 – Robert

+0

@Robert、あなたのenumのメンバーをループすることができますし、インスタンスを作成し、ループのためのリストに追加:http://stackoverflow.com/questions/972307/can-you-loop-through-all- enum-values – Habib

1

私はfuncsの辞書を使用します。

Dictionary<DtoSelection, Func<AbstractDto>> dictionary = 
     new Dictionary<DtoSelection, Func<AbstractDto>> 
{ 
    {DtoSelection.dto1,() => new dto1()} 
}; 

var dto = dictionary[DtoSelection.dto1](); 
+0

私は108回書くことを避けようとしています。私はすべてのタイプの辞書を構築する必要があります。 – Robert

1

Activator.CreateInstanceを使用してみてください:

return (AbstractDto)Activator.CreateInstance 
         (Type.GetType(((DtoSelection)id).ToString(), true, true); 

または代わりに、チートのビットを、あなたはこのためにいくつかのコード生成を使用することができます。

public static string GenerateValues() 
{ 
    StringBuilder sb = new StringBuilder(); 
    sb.AppendLine("DtoSelection selection = (DtoSelection)id;"); 
    sb.AppendLine("switch (selection)"); 
    foreach (DtoSelection value in (DtoSelection[])Enum.GetValues(typeof(DtoSelection)) 
    { 
     sb.AppendLine("case DtoSelection." + value.ToString() + ":"); 
     sb.AppendLine("return new " + value.ToString() + ";"); 
    } 
} 
0

あなたはIoCコンテナ(ユニティ、のStructureMap、NINject ...)

アンIocのを使用する必要があります許可する:

  • 名前をタイプするように登録する(コンテナによって異なります) ):

    Container.Register<AbstractDto,Dto1>(DtoSelection.dto1.ToString()); 
    
  • Container.Resolve<AbstractDto>(DtoSelection.dto1.ToString()); 
    

タイプはこれがあなたのためにインスタンス化のすべての詳細を処理します解決します。

その他のソリューションは、「Poor man's IoC」と呼ばれています。車輪を再構築しないでください。あなたは「コンストラクタ・インジェクション」を使用している場合は削除することができnew()制約(requirement of parameterless constructor):

public void RegisterDto<TDto>(DtoSelection dtoSelection) 
    where TDto : AbstractDto, new() 
    { 
    Container.Register<AbstractDto,Dto1>(dtoSelection.ToString()); 
    } 


    public TDto GetDto<TDto>(DtoSelection dtoSelection) 
    where TDto : AbstractDto 
    { 
    return Container.Resolve<AbstractDto>(dtoSelection.ToString()) as TDto; 
    } 

注:

はもちろん、あなたがメソッドの背後にあるコンテナを非表示にします。コンストラクタインジェクションでは、コンストラクタのパラメータとして使用される値を登録できます。このパラメータは、他のオブジェクトまたは抽象オブジェクト(インタフェース、抽象クラス)でもかまいません。これを有効にするには、このパラメータをcontianerに登録する必要があります。

あなたが選んだIoCは、「Poor man's IoC」に比べて多くの利点があります。

UPDATE

あなたがそれを書いて何回も避けたい場合は、ほとんどのIoCコンテナはまた、あなたがこのように登録を行うことができますので、名前で登録することができます:

// iterate the DtoSelection Enum 
    foreach(var e in Enum.GetValues(DtoSelection)) 
    { 
    DtoSelection dtoSel = (DtoSelection)e; 
    int n = (int)dtoSel; 
    Container.Register<AbstractDto>("Dto" + n, dtoSel.ToString()); 
    } 

注:最初のパラメータは型名(または完全型名)です。 2番目はそれを解決することを可能にする名前です。

+1

これは過剰IMOです。 –

+0

@newStackExchangeInstanceなぜ過度なのですか?あなたは単純にNugetパッケージを追加し、数行のコードを書く必要があります。あなたが "貧しい人のIoC"を書いている場合よりも簡単です。あなたは間違いを犯すのを避けるか、かっこいい細部を忘れることを避けてください。あなたが実装できるほとんどのものよりも、より安全かつ効率的に動作します。私にとっては、すでに解決された問題を解決するためにホイールを再発明しています...そしておそらく予期せぬバグを導入しています。 – JotaBe

+0

Activator.CreateInstanceまたは複雑なIoCフレームワークは、より複雑な(したがってバグが多い)ものは何ですか? –

0
public AbstractDto CreateDto(DtoSelection selection) 
{ 
    return (AbstractDto)Activator.CreateInstance(Type.GetType("Perhaps.Some.Qualifier.Here." + selection.ToString())); 
} 
関連する問題