gpt4 book ai didi

c# - 从命名值的 IEnumerable 设置实例的属性值

转载 作者:行者123 更新时间:2023-12-03 18:46:52 25 4
gpt4 key购买 nike

我有 2 个函数返回 IEnumerable<Stat> .

此函数返回属于 CharacterStats 的所有单个属性。类(class):

private IEnumerable<Stat> GetAllStats()
{
yield return Level;
yield return Health;
yield return Damage;
yield return Defense;
//several others
yield return LifePerSecond;
}

此函数从我新添加的 sqlite 中获取存储的(基本)值D b:
private IEnumerable<Stat> GetBaseStatsFromDB()
{
//connection code ...

while (rdr.Read())
{
yield return new Stat
{
Name = (Enums.StatName)Enum.Parse(typeof(Enums.StatName), rdr.GetString(1)),
MinValue = rdr.GetInt32(2),
MaxValue = rdr.GetInt32(3),
CurrentValue = rdr.GetInt32(4)
};
}

//close connection
}

我想做的是返回 CharacterStats 的新实例其中每个 Stat从数据库初始化并分配给实例,例如:
GetAllStats.ToList().ForEach( //apply matching stat from GetBaseStatsFromDB());

我能够成功地从数据库中获取值并创建一个新的 Stat每个对象。但是,我无法将这些值应用于 CharacterStats类(class)。

目前有大约 16 个统计数据,当我继续构建这个项目时,这些可能会被添加/删除,所以理想情况下,我想找到一种随着这个列表的变化而继续工作的方法。

如何应用 GetBaseStatsFromDB() 的结果到 CharacterStats 上的所有属性通过使用 GetAllStats()方法?

编辑澄清:
CharacterStats是一个拥有不同 Stat 的类s 生成。例子:
public class CharacterStats
{
public Stat Level;
public Stat Name;
...
public Stat LifePerSecond;
}
GetAllStats()是一个函数,用于一次枚举这些属性中的每一个(如列表)
GetBaseStatsFromDB()是我从数据库初始化这些值的尝试。我想做的是采取 每个单独的属性(property)CharacterStats并申请 匹配 来自 GetBaseStatsFromDB() 的统计数据.

所以... GetBaseStatsFromDB()将返回(除了其他):
Stat
{
Name = "Level",
MinValue = 1,
MaxValue = 50,
CurrentValue = 1
}

我想把这个结果应用到 Stat:Level CharacterStats 上的属性(property)类,然后重复所有其他统计信息。

最佳答案

反射是这里显而易见的答案(不是唯一的答案)。

首先,确保 Enums.StatName 的值名称与 CharacterStats 上的属性名称相同(我猜你还是这样做了,因为很明显)。

//  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());

但是如果我们可以分享 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));
}
}

@PanagiotisKanavos 指出(至少根据我们所见), Enums.StatName enum 根本没有必要。如果你只是使用 Name 的字符串,您可以在数据库中引入新的统计信息,而无需更改枚举。

如果您使用枚举来避免“魔术字符串”(也许某些统计信息在硬编码引用中通过名称引用),那么枚举是正确的做法,用于静态检查和 IntelliSense。但是您可能想考虑为代码需要按名称知道的统计信息保留一个枚举或只读全局变量,然后从数据库中接受任意字符串名称以获取代码中没有任何特殊状态的统计信息。不过,那是一座你今天不需要过的桥。

Panagiotis 还指出,您可以制作 CharacterStats Dictionary<String, Stat> 的子类,并且完全避免使用反射。这不是一个坏主意。一个缺点又是魔术字符串:例如,如果每个字符都有 Level , Damage等,代码具体与 Level交互, 然后制作 Level类属性是明智的。

关于c# - 从命名值的 IEnumerable<T> 设置实例的属性值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36289775/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com