对不起,如果这被问及回答,我搜索但认为我不知道词汇来找到答案。研究过反思,但这似乎不是答案吗?我显然是个新手。我正在尝试/为新的Battletech游戏的mod做出一点贡献。
我已经拥有此Dictionary
,并希望使用其键来设置属性,如下面的foreach
所示。我不知道这是在编译还是运行时,我的猜测是编译时...
我将* limb *作为伪代码放入我想象它可能会起作用的方式。属性mechDef.Head
是LocationLoadoutDef
类型的对象,其属性CurrentInternalStructure
为float
。
希望有意义!
非常需要任何帮助。
public class Settings {
public readonly Dictionary<string, bool> LimbRepair = new Dictionary<string, bool> {
{ "Head", false },
{ "LeftArm", false },
{ "RightArm", false },
{ "CenterTorso", false },
{ "LeftTorso", false },
{ "RightTorso", false },
{ "LeftLeg", false },
{ "RightLeg", false },
};
}
MechDef mechDef = new MechDef
(__instance.DataManager.MechDefs.Get(id), __instance.GenerateSimGameUID());
foreach (string limb in settings.LimbRepair.Keys) {
if (!settings.LimbRepair[limb]) {
mechDef.*limb*.CurrentInternalStructure = Math.Max
(1f, mechDef.*limb*.CurrentInternalStructure * (float)rng.NextDouble());
}
答案 0 :(得分:2)
使用Reflection非常容易,你可能会在这里得到几个答案,告诉你如何,但是既然你正在编写游戏,我猜你想要尽可能好的表现而且反思总是不会给你那个。
下面是一个不需要反射的解决方案,但仍允许您使用所需的循环结构。创建对象时只需要进行一些设置,然后就可以像访问字典一样访问属性。
首先,我们需要编写一个表示属性的实用程序类。由于属性可以是不同的类型,因此这是带有类型参数的泛型类。
class PropertyWrapper<T>
{
private readonly Func<T> _getter;
private readonly Action<T> _setter;
public PropertyWrapper(Func<T> getter, Action<T> setter)
{
_getter = getter;
_setter = setter;
}
public T Value
{
get
{
return _getter();
}
set
{
_setter(value);
}
}
}
这个类背后的想法是你创建它来表示你想要的任何属性,并调用它的方法来读取和设置属性。该类知道如何读取和设置属性,因为你告诉它在构造它时如何通过传递一个简短的lambda表达式来完成工作。
此实用程序允许您将表示肢体的所有属性放入字典中。然后你可以按字符串查找它们,就像你的设置一样。例如,您的MechDefinition可能如下所示:
class MechDef
{
public Limb Head { get; set; }
public Limb LeftArm { get; set; }
public Limb RightArm { get; set; }
public Limb LeftTorso { get; set; }
public Limb RightTorso { get; set; }
public Limb CenterTorso { get; set; }
public Limb RightLeg { get; set; }
public Limb LeftLeg { get; set; }
private readonly Dictionary<string, PropertyWrapper<Limb>> Properties;
public MechDef()
{
Properties = new Dictionary<string, PropertyWrapper<Limb>>
{
{"Head", new PropertyWrapper<Limb>( () => Head, v => Head = v ) },
{"LeftArm", new PropertyWrapper<Limb>( () => LeftArm, v => LeftArm = v ) },
{"RightArm", new PropertyWrapper<Limb>( () => RightArm, v => RightArm = v ) },
{"CenterTorso",new PropertyWrapper<Limb>( () => CenterTorso, v => CenterTorso = v )},
{"RightTorso", new PropertyWrapper<Limb>( () => RightTorso, v => RightTorso = v ) },
{"LeftTorso", new PropertyWrapper<Limb>( () => LeftTorso, v => LeftTorso = v ) },
{"RightLeg", new PropertyWrapper<Limb>( () => RightLeg, v => RightLeg = v ) },
{"LeftLeg", new PropertyWrapper<Limb>( () => LeftLeg, v => LeftLeg = v ) }
};
foreach (var property in Properties.Values) property.Value = new Limb();
}
public Limb this[string name]
{
get
{
return Properties[name].Value;
}
set
{
Properties[name].Value = value;
}
}
}
是的,那里有一些设置,但它只在一个地方,并且它只在你实例化MechDef时执行一次。现在,您可以通过字符串访问所有肢体:
foreach (var pair in settings.LimbRepair)
{
if (pair.Value != false) continue;
var limb = mechDef[pair.Key];
limb.CurrentInternalStructure = Math.Max
(
1.0F,
limb.CurrentInternalStructure * (float)rng.NextDouble()
);
}
答案 1 :(得分:1)
您可以创建一个DynamicObject来创建自己的动态词典See the explanation here
假设您要为访问提供替代语法 字典中的值,以便代替写作 sampleDictionary [&#34; Text&#34;] =&#34;示例文本&#34;,你可以写 sampleDictionary.Text =&#34;示例文本&#34;。
这是上述同一篇MSDN文章中的示例:
public class DynamicDictionary : DynamicObject
{
// The inner dictionary
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get { return dictionary.Count; }
}
// If you try to get a value of a property not defined
// in the class, this method is called.
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase so
// that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary, set the result parameter
// to the property value and return true. Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is not
// defined in the class, this method is called.
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Converting the property name to lowercase so that
// property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary, so this method always returns true.
return true;
}
}
这就是你如何使用DynamicDictionary:
dynamic person = new DynamicDictionary();
// Adding new dynamic properties. The TrySetMember method is called.
person.FirstName = "Ellen";
person.LastName = "Adams";
答案 2 :(得分:1)
反思是获得它的一种方式。 https://stackoverflow.com/a/1954663/83250实际上完美地回答了这个问题。然而,我会重构你的数据,所以mechDef
对象是另一个字典,但如果你必须保持它像你的问题,这将是有效的:
void Main()
{
Dictionary<string, bool> limbRepair = new Dictionary<string, bool>
{
{ "Head", false },
{ "LeftArm", false },
{ "RightArm", false },
// Etc.
};
MechDefinition mechDef = new MechDefinition();
List<Limb> limbs = new List<Limb>();
foreach (KeyValuePair<string, bool> limbsToRepair in limbRepair.Where(x => !x.Value))
{
Limb limb = mechDef.GetPropValue<Limb>(limbsToRepair.Key);
limb.CurrentInternalStructure = 9001;
}
}
public class MechDefinition
{
public MechDefinition()
{
Head = new Limb
{
Id = Guid.NewGuid(),
DateAdded = DateTime.Parse("2018-01-01"),
Name = "Main Head",
CurrentInternalStructure = 8675309
};
}
public Guid Id { get; set; }
public string Name { get; set; }
public int CurrentInternalStructure { get; set; }
public Limb Head { get; set; } = new Limb();
public Limb LeftArm { get; set; } = new Limb();
public Limb RightArm { get; set; } = new Limb();
// etc...
}
public class Limb
{
public Guid Id { get; set; }
public string Name { get; set; }
public DateTime DateAdded { get; set; }
public int CurrentInternalStructure { get; set; }
public bool IsDisabled { get; set; }
}
public static class ReflectionHelpers
{
public static object GetPropValue(this object obj, string name)
{
foreach (string part in name.Split('.'))
{
if (obj == null) { return null; }
Type type = obj.GetType();
PropertyInfo info = type.GetProperty(part);
if (info == null) { return null; }
obj = info.GetValue(obj, null);
}
return obj;
}
public static T GetPropValue<T>(this object obj, string name)
{
object retval = GetPropValue(obj, name);
if (retval == null) { return default(T); }
// throws InvalidCastException if types are incompatible
return (T)retval;
}
}
请注意,反射是一项非常昂贵的操作。如果您正在处理大量数据,那将是非常低效的。请查看https://stackoverflow.com/a/7478557/83250以获取效果概述。
同样在代码方面,我更喜欢完全远离动态和反思。当您需要访问属性属性时,Reflection有其特权,如果您没有强类型对象,则动态很好。话虽如此,C#是一种强类型语言,应尽可能对其进行处理。通过将mechDef
重命名为Dictionary<string, Limb>
对象或类似内容,您将获得更高效的应用。
答案 3 :(得分:1)
您始终可以创建经典且有效的if .. else
或switch
或者使用函数创建字典以更新正确的属性
public class Repair
{
public bool Active { get; set; }
public Action<MechDef> Update { get; set; }
}
public class Settings
{
public readonly Dictionary<string, Repair> LimbRepair =
new Dictionary<string, bool> {
{
"Head",
new Repair { Active = false, mechDef => mechDef.Head.CurrentInternalStructure = yourFunctionForHead }
},
{
"LeftArm",
new Repair { Active = false, mechDef => mechDef.LeftArm.CurrentInternalStructure = yourFunctionForLeftArm }
},
// ... and so on
};
}
然后在循环中,您将调用正确的更新操作,使用具有强类型和编译器帮助的优点的设置类变得更加清晰,从而防止动态运行时错误
var updates = settings.LimbRepair.Where(pair => pair.Value.Active == false)
.Select(pair => pair.Value);
foreach (var repair in updates)
{
repair.Update();
}
答案 4 :(得分:1)
如果我理解正确,你有类似的东西:
class LocationLoadoutDef
{
public LocationLoadoutDef()
{
Head = new Prop();
LeftArm = new Prop();
RightArm = new Prop();
CenterTorso = new Prop();
LeftTorso = new Prop();
RightTorso = new Prop();
LeftLeg = new Prop();
RightLeg = new Prop();
}
public Prop Head { get; set; }
public Prop LeftArm { get; set; }
public Prop RightArm { get; set; }
public Prop CenterTorso { get; set; }
public Prop LeftTorso { get; set; }
public Prop RightTorso { get; set; }
public Prop LeftLeg { get; set; }
public Prop RightLeg { get; set; }
...
}
class Prop
{
public float CurrentInternalStructure { get; set; }
...
}
因此,您可以使用反射获取对象的类型和属性。 这是基于您的伪代码的示例:
// your instance of LocationLoadoutDef
var mechDef = new LocationLoadoutDef();
//For reflection you need obtain the type
Type mechType = mechDef.GetType();
// loop your Dictionary
foreach (string limb in LimbRepair.Keys)
{
// If the property is false in the dictionary and the type has a property with that name
if (!LimbRepair[limb] && mechType.GetProperties().Any(p => p.Name == limb))
{
// Obtain the instance of the property
var property = mechType.GetProperty(limb).GetValue(mechDef) ;
// Get the property type
Type propertyType = property.GetType();
// If the property has a property CurrentInternalStructure
if (propertyType.GetProperties().Any(p => p.Name == "CurrentInternalStructure"))
{
// Obtain the current value for CurrentInternalStructure
var currentValue = propertyType.GetProperty("CurrentInternalStructure").GetValue(property);
// calculate the new value (I don't know what is rng)
var newValue = 1f ; //Math.Max(1f, (float)currentValue * (float)rng.NextDouble());
// set de value in the property
propertyType.GetProperty("CurrentInternalStructure").SetValue(property, newValue);
}
}
}