2017-01-16 7 views
0

APIデータを取得する際に使用するモデルと、エンティティフレームワークで使用するモデルを変換する変換クラスを作成しています。 2つが分離されている理由は、フィールド上のJSON.Net注釈によるものです.APIからデータを取得する際に必要なものと、entitfyフレームワーク& asp.netとの間で競合が発生します。メソッドを保存する方法ごとに若干の違いがあります。

私は1つのフィールドのためにほとんど同じであるクラスのダースを持っています。ここでは、それらの2つの変換メソッドの例を示します。

public static IEnumerable<PlayerUnitsKilledRank> ConvertPlayerUnitsKilledRankings(IEnumerable<ApiCombatUnitsKilledRank> rankings, int world) 
{ 
    List<PlayerUnitsKilledRank> dbRankings = new List<PlayerUnitsKilledRank>(); 
    DateTime now = DateTime.Now.Date; 
    foreach (ApiCombatUnitsKilledRank rank in rankings) 
    { 
     PlayerUnitsKilledRank dbRank = new PlayerUnitsKilledRank() 
     { 
      Date = now, 
      World = world, 
      Player = rank.Player, 
      Alliance = rank.Alliance, 
      Rank = rank.Rank, 
      UnitsKilled = rank.UnitsKilled 
     }; 
     dbRankings.Add(dbRank); 
    } 
    return dbRankings; 
} 

public static IEnumerable<PlayerCavernRaidingRank> ConvertPlayerCavernRaidingRankings(IEnumerable<ApiRaidingCavernRank> rankings, int world) 
{ 
    List<PlayerCavernRaidingRank> dbRankings = new List<PlayerCavernRaidingRank>(); 
    DateTime now = DateTime.Now.Date; 
    foreach (ApiRaidingCavernRank rank in rankings) 
    { 
     PlayerCavernRaidingRank dbRank = new PlayerCavernRaidingRank() 
     { 
      Date = now, 
      World = world, 
      Player = rank.Player, 
      Alliance = rank.Alliance, 
      Rank = rank.Rank, 
      Plundered = rank.ResourcesPlundered 
     }; 
     dbRankings.Add(dbRank); 
    } 
    return dbRankings; 
} 

冗長コードを削除してクラスDRYを維持するにはどうすればよいですか?方法はお互いに似ていますが、私は頭の上からこれを行う良い方法を考えることができません。

私はジェネリックメソッドを使うことができましたが、それでも私が扱う必要のあるオフプロパティは1つもありません。それぞれのクラスは非常に似ているので、すべて継承したベースクラスを作ることができますが、一回限りのプロパティはまだ問題です。

答えて

3

ApiCombatUnitsKilledRankApiRaidingCavernRankの共通のインターフェイスを抽出します。このインタフェースは、単一のメソッド、IRank ProduceRank()を持つことができます。

PlayerCavernRaidingRankおよびPlayerUnitsKilledRankは同じIRankインターフェイスを継承する必要があります。

あなたが参照している「ワンオフプロパティ」は、具体的な実装の懸案事項です。実際には、好きなだけ多くのプロパティを設定できます。

public interface IRank 
{ 
    // Your common rank properties here 
    // Maybe even create a base abstract Rank class ... 
} 

public interface IRankProducer 
{ 
    IRank ProduceRank(); 
} 

public class PlayerCavernRaidingRank : IRank 
{ 
} 

public class PlayerUnitsKilledRank : IRank 
{ 
} 

public class ApiCombatUnitsKilledRank : IRankProducer 
{ 
    public IRank ProduceRank() 
    { 
     return new PlayerUnitsKilledRank() 
     { 
      Player = this.Player, 
      Alliance = this.Alliance, 
      Rank = this.Rank, 
      UnitsKilled = this.UnitsKilled 
     }; 
    } 
} 

public class ApiRaidingCavernRank : IRankProducer 
{ 
    public IRank ProduceRank() 
    { 
     return new PlayerCavernRaidingRank() 
     { 
      Player = this.Player, 
      Alliance = this.Alliance, 
      Rank = this.Rank, 
      Plundered = this.ResourcesPlundered 
     }; 
    } 
} 

public static IEnumerable<IRank> Convert(IEnumerable<IRankProducer> rankings, int world) 
{ 
    var dbRankings = new List<IRank>(); 
    DateTime now = DateTime.Now.Date; 
    foreach (IRankProducer rank in rankings) 
    { 
     var rank = rank.ProduceRank(); 
     rank.World = world; 
     rank.Date = now; 
     dbRankings.Add(rank); 
    } 

    return dbRankings; 
} 
0

あなたはこの問題を解決するために、一般的なメソッドにデリゲートを渡すことができ、またはすべてのPlayerRankは、パラメータなしのコンストラクタを持っている場合は、new()制約を使用することができます。

public static IEnumerable<TPlayerRank> ConvertRankings<TApiRank,TPlayerRank>(IEnumerable<TApiRank> rankings, int world/*, Func<TPlayerRank> func*/) 
    where TApiRank : APIRank, 
    where TPlayerRank : PlayerRank, new() 
{ 
    List<TPlayerRank> dbRankings = new List<TPlayerRank>(); 
    DateTime now = DateTime.Now.Date; 
    foreach (var rank in rankings) 
    { 
     //TPlayerRank dbRank = func(); 
     var dbRank = new TPlayerRank(); 

     dbRank.Date = now, 
     dbRank.World = world, 
     dbRank.Player = rank.Player, 
     dbRank.Alliance = rank.Alliance, 
     dbRank.Rank = rank.Rank, 
     dbRank.Plundered = rank.ResourcesPlundered 

     dbRankings.Add(dbRank); 
    } 
    return dbRankings; 
} 

TApiRankは一般的なタイプです。 where TApiRank : APIRank、私はAPIRankがクラスだと仮定していますが、@HristoYankovは、一般的な提案インタフェースIRankを使用することをお勧めします。

1

ApiRankPlayerRankの両方の基本クラスを作成し、をApiRankベースクラスに公開することもできます。 ToString()のように考えてください。

abstract class PlayerRank 
{ 
    public DateTime Date { get; set; } 
    public int World { get; set; } 
    public int Player { get; set; } 
    public int Alliance { get; set; } 
    public int Rank { get; set;} 
} 

abstract class ApiRank 
{ 
    public int Player { get; set; } 
    public int Alliance { get; set; } 
    public int Rank { get; set; } 

    // method that should be overriden in 
    // concrete class that create specific player rank type 
    // as well as doing type specific operation 
    protected abstract PlayerRank CreatePlayerRank(); 

    // put common operation here 
    public PlayerRank ToPlayerRank(int world, DateTime date) 
    { 
     var inst = CreatePlayerRank(); 

     inst.Player = Player; 
     inst.Alliance = Alliance; 
     inst.Rank = Rank; 
     inst.World = world; 
     inst.Date = date; 

     return inst; 
    } 
} 

class PlayerUnitsKilledRank : PlayerRank 
{ 
    public int UnitsKilled { get; set; } 
} 

class ApiCombatUnitsKilledRank : ApiRank 
{ 
    public int UnitsKilled { get; set; } 

    protected override PlayerRank CreatePlayerRank() 
    { 
     var b = new PlayerUnitsKilledRank(); 
     b.UnitsKilled = UnitsKilled; 
     return b; 
    } 
} 

class PlayerCavernRaidingRank : PlayerRank 
{ 
    public int Plundered { get; set;} 
} 

class ApiRaidingCavernRank : ApiRank 
{ 
    public int Plundered { get; set;} 

    protected override PlayerRank CreatePlayerRank() 
    { 
     var b = new PlayerCavernRaidingRank(); 
     b.Plundered = Plundered; 
     return b; 
    } 
} 

static IEnumerable<PlayerRank> ConvertRank(IEnumerable<ApiRank> rankings, int world) 
{ 
    DateTime now = DateTime.Now.Date; 
    return rankings.Select(x=>x.ToPlayerRank(world, now)); 
} 
関連する問題