2017-01-16 36 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)); 
}