【问题标题】:Is it possible to grab a static class dynamically using enum?是否可以使用枚举动态获取静态类?
【发布时间】:2016-01-26 17:31:25
【问题描述】:

我想使用静态类为我的应用程序创建配置。

首先请原谅我的无知,我不是全职 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 统一的原因,这为开发人员提供了一种快速方法,可以为关卡设计师提供对象的选项列表。

因此,通过选择枚举值,关卡设计师可以设置存储在配置中的属性,而无需实际将值直接输入到对象中。这些值在初始化时针对对象设置。

在构造函数中,我想从传递的MaterialQuality 枚举值的静态配置值中为CostValue 设置成员变量。

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

    }

}

这种方法的主要原因是为配置提供单一位置,并为非技术人员提供一种相当简单的方法来更改应用程序的某些部分,而无需深入研究主要类。它还允许我利用智能感知中可用的常量。

【问题讨论】:

  • 您应该更好地解释您想要实现的目标,而不是如何改进您的解决方案,这在如何使用 C# 和 OOP(不仅在 C# 中)方面似乎是错误的设计。
  • 我可能应该提到这是一个统一项目的一部分。
  • 一小时内获得六个答案 - 哇...

标签: c# unity3d


【解决方案1】:

我喜欢使用字典进行这种类型的配置。

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
}

【讨论】:

  • 感谢您的回答,我非常喜欢这个,它仍然让我可以使用在 unity3d 中的枚举,它为开发人员提供了一种向关卡设计师呈现下拉选择的便捷方式。
  • 虽然似乎有很多方法可以实现对我需要的动态访问,但这种方法最适合产品构建和为非技术提供简单编辑并将配置与应用程序分离的限制逻辑。
  • 很高兴它对你有用 Rob!对于这些情况,我喜欢这种方法,因为它保留了您的枚举并将其作为您的堆栈响应方式的核心决策者。这往往是一种可重复的模式,并且可以轻松确保您不会添加或创建重复的配置。
【解决方案2】:

可能更好的方法是:

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;
    //...

【讨论】:

  • 感谢您的回答,这不是我所追求的,我想将MaterialQuality 的配置分开保留。 Config.cs 供非技术人员编辑,无需进入主 Material
【解决方案3】:

我会在 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;

    }
}

【讨论】:

  • 谢谢我喜欢这种方法,它将配置与Material 的主要逻辑分开,但它删除了enum 要求,这在大多数情况下是一件好事,但我实际上需要提供非- 具有简单配置选择的技术人员,unity3d 中的enum 是提供此功能的最简单方法,因为它为设计人员提供了一个简单的下拉选择。
【解决方案4】:

恕我直言,这不是静态类的好用法。您应该使用常规的面向对象编程来解决问题。

我发现所有材料质量都有 2 个共同属性:ValueCost。对我来说,这意味着你应该设计一个名为MaterialQuality的类:

public class MaterialQuality
{
     public float Value { get; set; }
     public int Cost { get; set; }
}

如果 material quality 是应用程序配置的一部分,我认为您应该设计一个 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 来添加材质质量也很容易:我们将把 public MaterialQualities 属性转换为 ImmutableList&lt;T&gt;所以你强制开发人员使用该方法添加材质这样做)并添加一个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 MaterialQuantity
  • @Rob 哦,是的,我错过了。我要编辑答案;)
  • 这在典型情况下看起来是个不错的方法,但是我实际上在 unity3d 项目中使用 c#,enum 为开发人员提供了一个简单的机制,允许关卡设计师选择对象的属性。
  • 是的,我很抱歉我应该早点标记它,但是我确实指定我想在原始问题中使用 enum 值访问配置。
  • @Rob 有时标签可能会改变问题的含义。虽然添加或删除标签是永远开放的,但如果你想得到好的答案,你需要尽可能具体;)
【解决方案5】:

怎么样:

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

}

【讨论】:

  • 感谢您的回答,这不是我所追求的,我想将MaterialQuality的配置单独保留在ex中。 Config.cs 供非技术人员在不进入主 Material 类的情况下进行编辑
【解决方案6】:

如果你没有广泛使用你的枚举,你可以这样做:

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

【讨论】:

  • 感谢您的回答,这不是我所追求的,我想将配置与应用程序逻辑分开并保留使用enum 以简化非技术级别的配置设计师。
猜你喜欢
  • 1970-01-01
  • 2014-06-01
  • 1970-01-01
  • 2015-12-07
  • 1970-01-01
  • 2015-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多