2017-01-16 40 views
0

我正在編寫一個轉換類來在拉動API數據時使用的模型之間進行轉換,使用實體框架來使用模型。這兩者之間的原因是由於字段上的JSON.Net註釋,當從api提取數據時以及在使用asp.net的授權框架時需要這些註釋。保持方法DRY在每種方法中都有細微的差異

我有幾十個這樣的類,除了單個字段幾乎完全相同。這裏有兩個轉換方法的例子。

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

你怎麼能刪除多餘的代碼,並保持我的班幹?這些方法彼此非常相似,但我想不出一個好辦法來做到這一點。

我可以使用泛型方法,但是我仍然需要單獨的屬性,我需要處理。因爲每個類都很相似,所以我可以創建一個它們都繼承的基類,但是一次性屬性仍然是一個問題。

回答

3

提取ApiCombatUnitsKilledRankApiRaidingCavernRank之間的通用接口。這個接口可以有一個方法:IRank ProduceRank()

PlayerCavernRaidingRankPlayerUnitsKilledRank應繼承相同的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基類中公開ToPlayerRank。想像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)); 
}