【问题标题】:Getting nth property of a class获取类的第 n 个属性
【发布时间】:2014-06-27 19:46:17
【问题描述】:

我是 C# 语言的初学者

我有这样的课

public  class Plan
{
       int a;
       int b;
       int c;     
}  

我可以以任何方式获得该类的第 n 个属性。

例如:planObject.propertyIndex

这对我的项目有很大帮助,因为我得到的索引号表示要更改其值的属性。我现在正在做的是使用 if...else 。

   if(index ==1)
   {
         planObject.a = 100;
   }
   else if(index ==2)    
   {
      planObject.b = 100;
   }

有没有其他方法可以通过反射解决这个问题?

【问题讨论】:

  • 使用单个 List<int>int[]Dictionary<int, int>
  • @TimSchmelter 实际上我的工作是代码维护的一部分,这就是代码的设计方式,我无法更改使用的数据结构
  • 这看起来是一个完全可以避免的问题。你最终想要达到什么目的?编辑:哎呀,那没关系。
  • 你应该使用反射:var props = typeof(Plan).GetProperties().ToArray()[n];
  • @Robert_Junior,只是为了说清楚。属性不是单独排序的,因此 nth property 在这里不是一个明确定义的术语。您需要以某种方式在这里定义顺序。

标签: c# asp.net


【解决方案1】:

可以使用反射,但是,我强烈反对。而是使用List<int>int[] 之类的集合。在这种情况下,由于您想获得 nth int 值,您还可以使用 Dictionary<int, int>

public  class Plan
{
    Dictionary<int, int> Values;

    public Plan()
    {
        Values = new Dictionary<int, int>();
        Values.Add(1, 100);
        Values.Add(2, 200);
        Values.Add(3, 300);
    }

    // ...
}

现在您可以通过数字访问值:

int value = Values[1]; // 100 

这是一个列表版本:

public  class Plan
{
    List<int> Values = new List<int>();

    public Plan()
    {
        Values.Add(100);
        Values.Add(200);
        Values.Add(300);
    }

    // ...
}

您通过(从零开始的)索引访问它:

int value = Values[0]; // 100 

【讨论】:

  • 据我了解,他无法改变Plan的结构。
  • @iknownothing 绝对不能更改数据结构。我如何使用反射来实现它。任何帮助将不胜感激
  • @Robert_Junior,反射是可能的。我为您提供了一个示例,但请记住,它可能不推荐使用。
  • @Robert_Junior,在可能的情况下使用直接访问总是更好,但在你的情况下,这听起来是必须的。反射有两个陷阱:可读性和性能。它的可读性不如直接访问,而且在大量使用时性能较差。
  • @Robert_Junior:我还没有时间给你一个反射解决方案。但是你为什么不能改变你自己的班级呢?如果您是初学者,请不要以错误的方式开始它,因为您将把它放在一个非常不稳定的基础上。
【解决方案2】:

一句警告,这根本不适合初学者。它可能只会使代码更复杂。这个答案理所当然地认为您具有扩展方法和反射的工作知识。

public static class PlanExtension
{
  PropertyInfo _info = typeof(Plan).GetProperties();

  public static void SetValue(this Plan plan, int index, int value)
  {
    var prop = _info[index - 1]; // So 1 maps to 0.. or 1 in this case
    prop.SetValue(plan, value, null);
  }

  public static int GetValue(this Plan plan, int index)
  {
    var prop = _info[index - 1]; // Mapping magic
    return (int) prop.GetValue(plan, null);
  }
}

这样称呼:

var p = new Plan();
p.SetValue(1, 139); // "a"
var b = p.GetValue(2); // "b"

如果您对属性有一个可定义的顺序(例如名称或其他内容),这将有所帮助。此外,在反射方面必须进行错误处理。

【讨论】:

    【解决方案3】:

    没有“按索引进行属性”功能,但一种更容易使用的方法是在类上构建索引器并在其中封装 switch 语句。也许是这样的:

    public class Plan
    {
        public int this[int index]
        {
            get
            {
                switch (index)
                {
                    case 1:
                        return this.a;
                    ...
                }
            }
            set
            {
                switch (index)
                {
                    case 1:
                        this.a = value;
                    ...
                }
            }
        }
    }
    

    所以,现在使用它看起来像这样:

    planObject[i] = 100;
    

    现在,在您的情况下,看起来您还有一个额外的需求,因为您有一个 key(索引)和一个 value(例如 100),因此您需要将键和值存储在 Dictionary 中。因此,在您使用 Plan 的类中创建一个 private field

    private Dictionary<int, int> _values = new Dictionary<int, int>
    {
        { 1, 100 },
        { 2, 200 },
        ...
    }
    

    要使用字典,您可以这样做:

    planObject[i] = _values[i];
    

    更新:如果您无法更改课程Plan,那么您需要执行类似的操作。首先,您需要一个从索引到属性名称的映射:

    private Dictionary<int, string> _properties = new Dictionary<int, string>
    {
        { 1, "a" },
        { 2, "b" },
        ...
    }
    

    接下来您需要设置该属性:

    var t = planObject.GetType();
    var p = t.GetProperty(_properties[i]);
    if (p != null)
    {
        p.SetValue(planObject, 100);
    }
    

    【讨论】:

      【解决方案4】:

      如果你必须使用对象,而不是建议的集合。

      Plan b = new Plan();
      Type t = new Type(b.GetType());
      var properties = t.GetProperties();
      for(int index = 0; index < properties.Length; index++)
      {
          properties[index].SetValue(b, 100);  
      }
      

      您可以在properties 数组中传递您自己的索引,而不是使用循环。 希望对你有帮助。

      【讨论】:

      • Setvalue 需要 3 个参数
      • @Robert_Junior 尝试在第三个中传递 null。 .Net 4.5 中提供了带两个参数的 SetValue。
      【解决方案5】:

      这就是你想要的

      public class Foo 
      {
          public int A {get;set;}
          public string B {get;set;}
          public object GetPropertyValueAt(int index)
          {
              var prop = this.GetType().GetProperties()[index];
              return prop.GetValue(this, null);
          }
      }
      

      用法

      Foo foo = new Foo() {A = 1, B = "abc"};
      int valueA = (int)foo.GetPropertyValueAt(0);
      string valueB = (string)foo.GetPropertyValueAt(1);
      int valueUnknown = (int)foo.GetPropertyValueAt(2); //<--- this line will give you an exception.
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-08-09
        • 2010-11-10
        • 2021-12-14
        • 2018-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-01-14
        相关资源
        最近更新 更多