【问题标题】:C# array of propertiesC# 属性数组
【发布时间】:2013-02-25 08:36:59
【问题描述】:

我有几个 get 属性,我希望它们能够像函数数组一样循环。我希望能够做这样的事情

public int prop1 { get; }
public string prop2 { get; }
public int[] prop3 { get; }
public int prop4 { get; }
public string prop5 { get; }
public string prop6 { get; }

Func<var> myProperties = { prop1, prop2, prop3, prop4, prop5, prop6 };

ArrayList myList = new ArrayList();
foreach( var p in myProperties)
{
    myList.Add(p);
}

这段代码很糟糕,但我认为它传达了我希望能够做什么的想法。有谁知道我怎么能做到这一点?

【问题讨论】:

  • documentation for Func&lt;TResult&gt; 向您展示了至少四种正确创建它们的方法。此外,考虑到代码中有多少损坏,您应该花更多时间阅读 C# 教程。
  • 如果不使用反射,您将不得不创建一个数据结构(例如List)来保存对每个属性的引用;然后遍历该数据结构。

标签: c# arrays properties getter


【解决方案1】:

您可以使用反射来访问您的类型中的属性:

class MyType
{
    public int prop1 { get; }
    public string prop2 { get; }
    public int[] prop3 { get; }
    public int prop4 { get; }
    public string prop5 { get; }
    public string prop6 { get; }

    public List<string> GetAllPropertyValues()
    {
        List<string> values = new List<string>();
        foreach (var pi in typeof(MyType).GetProperties())
        {
            values.Add(pi.GetValue(this, null).ToString());
        }

        return values;
    }
}

请注意,反射很慢,如果有更好的方法,您不应该使用它。例如,当您知道只有 6 个属性时,只需逐个查看即可。

【讨论】:

    【解决方案2】:

    你可以尝试使用GetProperties

    GetProperties Documentation

    例子:

    PropertyInfo[] myPropertyInfo;
    // Get the properties of 'Type' class object.
    myPropertyInfo = Type.GetType("System.Type").GetProperties();
    Console.WriteLine("Properties of System.Type are:");
    for (int i = 0; i < myPropertyInfo.Length; i++)
    {
        Console.WriteLine(myPropertyInfo[i].ToString());
    }
    

    更多信息:
    GetProperties with flags 的示例非常好,如果您想访问属性的特定子集(仅像公共属性),它对您很有用

    【讨论】:

      【解决方案3】:

      代码离工作不远了。 myProperties 变量应该是一个数组,您需要创建从属性读取的函数。 (属性getter实际上是作为一个函数来实现的,但是你不能把它作为一个函数来调用或者获取它的引用。)然后你通过调用它们来使用它们。

      public class MyClass {
      
        public int prop1 { get; set; }
        public string prop2 { get; set; }
        public int[] prop3 { get; set; }
        public int prop4 { get; set; }
        public string prop5 { get; set; }
        public string prop6 { get; set; }
      
        public ArrayList GetProperties() {
      
          Func<object>[] myProperties = {
            () => prop1, () => prop2, () => prop3,
            () => prop4, () => prop5, () => prop6
          };
      
          ArrayList myList = new ArrayList();
          foreach (var p in myProperties) {
            myList.Add(p());
          }
      
          return myList;
        }
      
      }
      

      【讨论】:

        【解决方案4】:

        如果您已经知道要循环的所有属性,那么您可以试试这个

        List<Reflection.PropertyInfo> myProperties = new List()<object>
        {
            typeof(SomeType).GetProperty("prop1"), 
            typeof(SomeType).GetProperty("prop2"), 
            typeof(SomeType).GetProperty("prop3"), 
            typeof(SomeType).GetProperty("prop4"), 
            typeof(SomeType).GetProperty("prop5"), 
            typeof(SomeType).GetProperty("prop6")
        };
        
        foreach(var p in myProperties)
        {
            var value = p.GetValue(someObject, new object[0]);
            myList.Add(p);
        }
        

        如果没有,你可以使用这样的东西:

        var myProperties = 
            from pi in someObject.GetType().GetProperties()
            select new 
            {
                pi.Name, 
                Value = pi.GetValue(object, new object[0])
            };
        
        foreach(var p in myProperties)
        {
            myList.Add(p.Value);
        }
        

        【讨论】:

        • 这将只保存每个属性的值,并且在不重新加载 List 的情况下不会反映对属性(或更确切地说是支持字段)的更新。
        • prop1, ..., prop6 应该是什么?
        • @poke 我不完全确定您是要引用属性本身还是仅引用它们的值。我已经更新了我的答案,以解释如何以两种不同的方式获得两者。
        • @KennethK。我不确定 OP 是要创建实际属性列表还是它们的值列表。
        • 只是指出这一点,以便每个阅读帖子的人都清楚。 (当然,自从您编辑后,它现在不适用!):)
        【解决方案5】:

        如果您需要数组中的属性,因为您需要(和我一样)设置和/或获取多个相关(且类型相同)的属性,您可以这样做。我知道反射是“'慢'”,但对于我的用例,重复代码(以及因此错误机会)减少的好处远远超过反射带来的任何“'慢'”(微不足道)。这不处理索引属性,但可以很容易地从中创建一个版本。

        ` 公共课 MyClass {

            private string[] myBoolPropertyNames = 
            {
                nameof(MyBool1Property),
                nameof(MyBool2Property)
            }; // MyBoolPropertyNames =
        
            private MyClass()
            {
                foreach (var propertyName in myBoolPropertyNames)
                {
        
                    ReflectionHelper.SetPropertyValue
                    (
                        parentObject: this,
                        propertyName: propertyName,
                        untypedPropertyValue: true
                    ); // SetPropertyValue
        
                } // foreach (var propertyName in myBoolPropertyNames)
        
                foreach (var propertyName in myBoolPropertyNames)
                {
        
                    bool boolPropertyValue = ReflectionHelper.GetPropertyValue<bool>
                    (
                        parentObject: this,
                        propertyName: propertyName
                    ); // SetPropertyValue
        
                    Console.WriteLine($"Property '{propertyName}' value: {boolPropertyValue}");
        
                } // foreach (var propertyName in myBoolPropertyNames)
            }
        
            public bool MyBool1Property { get; set; }
            public bool MyBool2Property { get; set; }
        
        } // MyClass
        

        `

        ` 公共类 ReflectionHelper {

            public static PropertyType GetPropertyValue<PropertyType>
            (
                object parentObject,
                string propertyName
            )
            {
                if (parentObject == null)
                {
                    throw new ArgumentException
                    (
                        $"Missing '{nameof(parentObject)}'."
                    );
                } // if (parentObject == null)
        
                PropertyInfo propertyInfo = parentObject.GetType().GetProperty(propertyName);
                if (propertyInfo == null)
                {
                    throw new ArgumentException
                    (
                        "No PropertyInfo found for Property: " + propertyName
                    );
                } // if (propertyInfo == null)
        
                object untypedPropertyValue = propertyInfo.GetValue(obj: parentObject);
        
                Type propertyType = 
                (
                    Nullable.GetUnderlyingType(propertyInfo.PropertyType) 
                    ?? propertyInfo.PropertyType
                ); // propertyType = 
        
                object typedPropertyValue = 
                (
                    (untypedPropertyValue == null) 
                    ? null 
                    : Convert.ChangeType(untypedPropertyValue, propertyType)
                ); // typedPropertyValue = 
        
                return (PropertyType)typedPropertyValue;
        
            } // GetPropertyValue
        
            public static void SetPropertyValue
            (
                object parentObject,
                string propertyName,
                object untypedPropertyValue
            )
            {
                if (parentObject == null)
                {
                    throw new ArgumentException
                    (
                        $"Missing '{nameof(parentObject)}'."
                    );
                } // if (parentObject == null)
        
                PropertyInfo propertyInfo = parentObject.GetType().GetProperty(propertyName);
                if (propertyInfo == null)
                {
                    throw new ArgumentException
                    (
                        "No PropertyInfo found for Property: " + propertyName
                    );
                } // if (propertyInfo == null)
        
                Type propertyType = 
                (
                    Nullable.GetUnderlyingType(propertyInfo.PropertyType) 
                    ?? propertyInfo.PropertyType
                ); // propertyType = 
        
                object typedPropertyValue =
                (
                    (untypedPropertyValue == null)
                    ? null
                    : Convert.ChangeType(untypedPropertyValue, propertyType)
                ); // typedPropertyValue = 
        
                propertyInfo.SetValue
                (
                    obj: parentObject, 
                    value: typedPropertyValue
                ); // propertyInfo.SetValue
        
            } // SetPropertyValue
        
        } // ReflectionHelper
        

        `

        【讨论】:

          【解决方案6】:

          您可以使用数组缓冲区并从中获取所有道具。通过这种方式,您可以非常快速地获取和设置:

          public object[] buf = new object[5];
          public int prop1 { get => buf[0]; }
          public string prop2 { get => buf[1]; }
          public int[] prop3 { get => buf[2]; }
          public int prop4 { get => buf[3]; }
          public string prop5 { get => buf[4]; }
          public string prop6 { get => buf[5]; }
          

          现在可以使用buf访问所有道具:

          foreach (var item in buf) {
            myList.Add(item);
          }
          

          或直接访问:

          buf[1] = 10;
          x = buf[1];
          

          【讨论】:

            猜你喜欢
            • 2013-07-07
            • 1970-01-01
            • 1970-01-01
            • 2019-10-26
            • 2013-05-17
            • 2019-02-16
            • 2019-11-24
            • 2019-07-11
            • 2012-12-03
            相关资源
            最近更新 更多