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