是否可以使用枚举动态获取静态类
本文关键字:获取 静态类 动态 枚举 可以使 是否 | 更新日期: 2023-09-27 18:31:53
我想使用静态类为我的应用程序创建配置。
首先请原谅我的无知,我不是全职的 c# 开发人员。我来自Ruby/Javascript世界,在这个世界里,对常量和变量的动态访问是微不足道的。
无论这是否是正确的方法,我目前都不是 100%。其他建议的方法会很棒。
我的配置有以下静态类设置:
public static class Config
{
public static class MaterialQuality
{
public static class Low
{
public const float Value = 0.1f;
public const int Cost = 10;
}
public static class Medium
{
public const float Value = 0.2f;
public const int Cost = 20;
}
public static class High
{
public const float Value = 0.2f;
public const int Cost = 40;
}
}
}
然后我有一个类Material
,它传递了一个与上述类型相关的枚举值Low,Medium,High
。enum
Unity 的原因为开发人员提供了一种快速的方法,可以为关卡设计师提供对象的选项列表。
因此,通过选择枚举值,关卡设计器可以设置存储在配置中的属性,而无需实际将值直接输入到对象上。初始化对象时,将针对对象设置这些值。
在构造函数中,我想从传递的MaterialQuality
枚举值的静态配置值中为 Cost
和 Value
设置成员变量。
public enum MaterialQuality
{
Low,Medium,High
}
public class Material
{
private int Cost;
private float Value;
Material(MaterialQuality quality) {
Cost = Config.MaterialQuality.<quality>.Cost;
Value = Config.MaterialQuality.<quality>.Value;
//in Javascript I'd use associative array access to the object
Cost = Config.MaterialQuality[quality].Cost;
//in Ruby we have const_get() on classes.
Cost = Config.MaterialQuality.const_get(quality).Cost
}
}
这种方法的主要原因是为配置提供单一位置,并为非技术人员提供一种相当简单的方式来更改应用程序的各个部分,而无需深入研究主类。此外,它还允许我利用智能感知中可用的常量。
我喜欢为这种类型的配置使用字典。
void Main()
{
var config = Config.Qualities[MaterialQualities.Low];
var cost = config.Cost;
var value = config.Value;
}
public static class Config
{
public static Dictionary<MaterialQualities, MaterialQuality> Qualities =
new Dictionary<MaterialQualities, MaterialQuality>
{
{ MaterialQualities.Low, new MaterialQuality { Value = 0.1F, Cost = 10 }},
{ MaterialQualities.Medium, new MaterialQuality { Value = 0.2F, Cost = 20 }},
{ MaterialQualities.High, new MaterialQuality { Value = 0.2F, Cost = 40 }},
};
}
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
public enum MaterialQualities
{
Low, Medium, High
}
可能更好的方法是:
public static class Config
{
public class Material
{
public Material(float value, int cost){
Value = value;
Cost = cost;
}
public float Value {get; private set;}
public int Cost {get; private set;}
public Material GetFor(MaterialQuality quality){
switch(quality){
case MaterialQuality.Low: return new Material(0.1f, 10);
case MaterialQuality.Medium: return new Material(0.2f, 20);
case MaterialQuality.High: return new Material(0.2f, 40);
}
throw new Exception("Unknown material quality " + quality);
}
}
}
稍后您可以使用它:
//....
Material materialData = Material.GetFor(quality);
Cost = materialData.Cost;
Value = materialData.Value;
//...
我会在MaterialQuantity中使用结构和静态属性而不是枚举。如下所示:
public struct MaterialQualityInfo
{
public MaterialQualityInfo( float value, int cost )
{
Value = value;
Cost = cost;
}
public float Value { get; private set; }
public int Cost { get; private set; }
}
public static class Config
{
public static class MaterialQuality
{
public static MaterialQualityInfo Low
{
get { return new MaterialQualityInfo( 0.1f, 10 ); }
}
public static MaterialQualityInfo Medium
{
get { return new MaterialQualityInfo( 0.2f, 20 ); }
}
public static MaterialQualityInfo High
{
get { return new MaterialQualityInfo( 0.2f, 40 ); }
}
}
}
public class Material
{
private int Cost;
private float Value;
Material( MaterialQualityInfo quality )
{
Cost = quality.Cost;
Value = quality.Value;
}
}
我直言,这不是静态类的良好用法。您应该使用常规的面向对象编程来解决此问题。
我看到所有材料质量都有 2 个共同属性: Value
和 Cost
.对我来说,这意味着你应该设计一个名为MaterialQuality
的类:
public class MaterialQuality
{
public float Value { get; set; }
public int Cost { get; set; }
}
如果材料质量是应用程序配置的一部分,我看到您应该按如下方式设计一个Configuration
类:
public class Configuration
{
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
。如果要初始化每个应用程序生命周期的配置,可以使用静态字段初始值设定项改进Configuration
类:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
public static Configuration Current => _current;
public List<MaterialQuality> MaterialQualities { get; } = new List<MaterialQuality>();
}
现在,向当前配置添加新的材料质量就像以下代码一样简单:
Configuration.Current.MaterialQualities.Add(new MaterialQualities { Value = 0.1f, Cost = 10 });
如果你想提供一个流畅的 API 来添加材料质量也很容易:我们将把公共MaterialQualities
属性变成一个ImmutableList<T>
(所以你强制开发人员使用该方法添加材料)并添加一个AddMaterial
方法:
public class Configuration
{
private readonly static Configuration _current = new Configuration();
private readonly List<MaterialQuality> _materialQualities = new List<MaterialQuality>();
public static Configuration Current => _current;
public IImmutableList<MaterialQuality> MaterialQualities => _materialQualities.ToImmutableList();
public Configuration AddMaterial(float value, int cost)
{
_materialQualities.Add(new MaterialQuality { Value = value, Cost = cost });
return this;
}
}
。现在添加许多材料看起来会更好!
Configuration.Current.AddMaterial(0.1f, 10)
.AddMaterial(0.2f, 20)
.AddMaterial(0.2f, 40);
怎么样:
public enum MaterialQuality
{
Low, Medium, High
}
public class Material
{
private int Cost;
private float Value;
private readonly Dictionary<MaterialQuality, Tuple<int, float>> storageMap = new Dictionary<MaterialQuality, Tuple<int, float>>
{
{ MaterialQuality.Low, Tuple.Create(10, 0.1f)},
{ MaterialQuality.Low, Tuple.Create(20, 0.2f)},
{ MaterialQuality.Low, Tuple.Create(40, 0.2f)},
};
public Material(MaterialQuality quality)
{
Cost = storageMap[quality].Item1;
Value = storageMap[quality].Item2;
}
}
如果你没有广泛使用你的枚举,你可以做如下的事情:
public class Material
{
public float Value { get; private set; }
public int Cost { get; private set; }
public Material(float value, int cost)
{
Value = value;
Cost = cost;
}
public static Material Low { get { return new Material(0.1f, 10); } }
public static Material Medium { get { return new Material(0.2f, 20); } }
public static Material High { get { return new Material(0.2f, 40); } }
}
然后:
var myLowMaterial = Material.Low;
var myMediumMaterial = Material.Medium;
var myHighMaterial = Material.High;
除非您使用enum
进行某些操作,否则您可以添加:
public static Material Get(MaterialQuality quality)
{
switch(quality)
{
case MaterialQuality.Low:
return Low;
case MaterialQuality.Medium:
return Medium;
case MaterialQuality.High:
return High;
}
throw new Exception("We should never go here");
}