C# 在IEnumerable中的实例上设置属性值<;T>;命名值的定义
我有两个函数返回一个C# 在IEnumerable中的实例上设置属性值<;T>;命名值的定义,c#,linq,sqlite,C#,Linq,Sqlite,我有两个函数返回一个IEnumerable 此函数返回属于CharacterStats类的所有单个属性: private IEnumerable<Stat> GetAllStats() { yield return Level; yield return Health; yield return Damage; yield return Defense; //several others yield return LifePerSeco
IEnumerable
此函数返回属于CharacterStats
类的所有单个属性:
private IEnumerable<Stat> GetAllStats()
{
yield return Level;
yield return Health;
yield return Damage;
yield return Defense;
//several others
yield return LifePerSecond;
}
我想做的是返回一个新的CharacterStats
实例,其中每个Stat
都从数据库初始化并分配给该实例,类似于:
GetAllStats.ToList().ForEach( //apply matching stat from GetBaseStatsFromDB());
我能够成功地从数据库中获取值,并从每个数据库中创建一个新的Stat
对象。但是,我无法将这些值应用于CharacterStats
类
目前大约有16个统计数据,在我继续构建这个项目时,这些数据可能会被添加/删除,因此理想情况下,我希望找到一种方法,在列表更改时继续工作
如何使用GetAllStats()
方法将GetBaseStatsFromDB()
的结果应用于CharacterStats
上的所有属性
编辑澄清:
CharacterStats
是一个类,它保存生成的不同的Stat
s。例如:
public class CharacterStats
{
public Stat Level;
public Stat Name;
...
public Stat LifePerSecond;
}
GetAllStats()
是一个函数,用于一次一个地枚举这些属性(如列表)
GetBaseStatsFromDB()
是我试图从DB初始化这些值的尝试。我想做的是在CharacterStats
上获取每个单独的属性,并应用GetBaseStatsFromDB()中的匹配属性
所以GetBaseStatsFromDB()
将返回(除其他外):
我想将这个结果应用到CharacterStats
类上的Stat:Level
属性,然后对所有其他统计重复上述操作。反射是这里显而易见的答案(不是唯一的答案)
首先,确保Enums.StatName
的值的名称与CharacterStats
上的属性名称相同(我猜您还是这样做了,因为这很明显)
但是,如果我们可以共享Stat
实例(此代码中没有任何内容阻止这一点),那么在复制Stat
实例时克隆它们会更安全:
public Stat() { ... }
public Stat(Stat copyMe)
{
this.Name = copyMe.Name;
this.MinValue = copyMe.MinValue;
this.MaxValue = copyMe.MaxValue;
this.CurrentValue = copyMe.CurrentValue;
}
……然后
// This version is much safer.
public void SetStats(IEnumerable<Stat> stats)
{
var cstype = this.GetType();
foreach (var stat in stats) {
var prop = cstype.GetProperty(stat.Name.ToString());
prop.SetValue(this, new Stat(stat));
}
}
//这个版本更安全。
公共无效设置状态(IEnumerable stats)
{
var cstype=this.GetType();
foreach(统计中的var stat){
var prop=cstype.GetProperty(stat.Name.ToString());
属性设置值(此,新统计(统计));
}
}
@PanagiotisKanavos指出(至少根据我们所看到的),根本不需要使用Enums.StatName
enum。如果只使用字符串作为名称
,则可以在数据库中引入新的统计信息,而无需更改枚举
如果您使用枚举来避免“神奇字符串”(可能某些统计数据在硬编码引用中按名称引用),那么对于静态检查和智能感知,枚举是正确的做法。但是,您可能需要考虑为代码需要按名称了解的统计数据保留一个枚举或只读全局变量,然后为代码中没有任何特殊状态的统计数据接受数据库中的任意字符串名称。这是一座你今天不需要跨越的桥
Panagiotis还指出,您可以将CharacterStats
作为字典
的子类,并避免与反射混淆。这主意不错。还有一个缺点是神奇字符串:例如,如果每个字符都有级别
,损坏
,等等,并且代码专门与级别
交互,那么将级别
设为类属性是明智的 动词apply
不适用于可枚举项,对于IEnumerable上的任何操作也不需要ForEach
。这个问题没有多大意义。什么是CharacterStats
,它与Stats
有什么关系?你想干什么?创建两个列表的组合,如外部联接?还是将每个数据库行作为同一对象的单独CharacterStats
属性的值?如果是这样的话,GetAllStats
与这个问题有什么关系?@PanagiotisKanavos我已经更新了这个问题,试图澄清我在问什么事实上,GetAllStats
枚举根本不需要,因为从数据库返回的Stat.name
值已经提供了属性名,如果OP只想将DB结果限制为特定属性,那么最好在中提供属性名称作为过滤器,其中propName在(..)
clause@PanagiotisKanavosTrue:只要将其设置为字符串,并在GetProperty()时引发异常返回null。prop.SetValue
是否应用Stat
对象的所有属性?此类中有4个属性。@levelonehuman,prop
实例用于您在其参数中命名的属性:GetType().GetProperty(“Level”)。SetValue(this,stat)
将设置this.Level
的值,而不设置其他值。
// Instance method of CharacterStats
public void SetStats(IEnumerable<Stat> stats)
{
var cstype = this.GetType();
foreach (var stat in stats) {
var prop = cstype.GetProperty(stat.Name.ToString());
prop.SetValue(this, stat);
}
}
// Toss in a constructor too.
public CharacterStats(IEnumerable<Stat> stats)
{
SetStats(stats);
}
// And a factory method
public static FromStats(IEnumerable<Stat> stats)
{
return new CharacterStats(stats);
}
var stats = new CharacterStats(GetBaseStatsFromDB());
var stats2 = CharacterStats.FromStats(GetBaseStatsFromDB());
// later on, maybe you want to copy stats from one to another...
stats.SetStats(stats2.GetStats());
public Stat() { ... }
public Stat(Stat copyMe)
{
this.Name = copyMe.Name;
this.MinValue = copyMe.MinValue;
this.MaxValue = copyMe.MaxValue;
this.CurrentValue = copyMe.CurrentValue;
}
// This version is much safer.
public void SetStats(IEnumerable<Stat> stats)
{
var cstype = this.GetType();
foreach (var stat in stats) {
var prop = cstype.GetProperty(stat.Name.ToString());
prop.SetValue(this, new Stat(stat));
}
}