我正在编写一个转换类,用于在提取API数据时使用的模型之间进行转换,执行与实体框架一起使用的模型。两者分开的原因是由于字段上的JSON.Net注释,从api中提取数据时以及在使用权限框架和数据时使用它之间存在冲突。 asp.net。
除了单个字段外,我还有十几个几乎相同的类。以下是两种转换方法的示例。
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;
}
你怎么能删除多余的代码并保持我的课干?这些方法彼此非常相似,但我无法想到一个很好的方法来做到这一点。
我可以使用泛型方法,但是我仍然需要处理单个off-property。由于每个类都非常相似,我可以创建一个他们都继承的基类,但是一次性属性仍然是一个问题。
答案 0 :(得分:3)
提取ApiCombatUnitsKilledRank
和ApiRaidingCavernRank
之间的公共接口。此接口可以使用单个方法:IRank ProduceRank()
。
PlayerCavernRaidingRank
和PlayerUnitsKilledRank
应该继承相同的IRank
界面。
一次性物业&#39;你所指的现在是一个具体的实现问题,你实际上可以拥有任意数量的这类属性。
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;
}
答案 1 :(得分:1)
您还可以为ApiRank
和PlayerRank
创建基类,并在ToPlayerRank
基类中公开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));
}
答案 2 :(得分: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
。