.net 从指定的非静态类(C#)中获取所有属性及其数据类型、值和名称

11dmarpk  于 2023-06-25  发布在  .NET
关注(0)|答案(2)|浏览(134)

我们有一个这样的(测试)类:

class Animal
{
    public string AnimalName { get; set; }
    public string AnimalType { get; set; }
    public int AnimalAgeInMonths { get; set; }
}

...和对象(或引用)到类:

Animal animal = new Animal();
animal.AnimalName = null; // No name yet
animal.AnimalType = "Sheep";
animal.AnimalAgeInMonths = 7;

所以我需要一个返回System.Collections.Generic.List<(string[], string[], string[])>的方法。第一个字符串数组表示所有属性的名称(即AnimalNameAnimalType等)、第二数组值(即 nullSheep等),以及第三个数组-数据类型,例如:

  • System.Int32用于int
  • System.Single用于float
  • System.String用于string
  • 等等

(这些可以使用typeof关键字生成)。
所以总的来说,我需要一个这样的方法:

public List<(string[], string[], string[])> GetClassPropertyInfo(object Class)

可以这样称呼:

GetClassPropertyInfo(animal);

只是告诉,我确实搜索了大约10分钟找到最匹配的答案,但没有找到我正在寻找的(例如,我会找到一个答案,但不知道如何获取数据类型,或者反过来),并且还尝试手动创建这个代码超过3次,当然是在System.Reflection命名空间的帮助下,但它没有工作。类似的问题也没有任何类似的问题,我最终放弃了。
我尝试了这个(第四次尝试):

using System;
using System.Reflection;
using System.Collections.Generic;

// FYI: Coded on an online compiler to save myself a lot of time

namespace TestAttempt
{
    public class Animal
    {
        public string AnimalName { get; set; }
        public string AnimalType { get; set; }
        public int AnimalAgeInMonths { get; set; }
    }
    
    public class Program
    {
        static void Main()
        {
            Animal a = new Animal();
            a.AnimalName = "";
            a.AnimalType = "Sheep";
            a.AnimalAgeInMonths = 7;
            
            List<(string[], string[], string[])> types = new Program().GetClassPropertyInfo(a, typeof(Animal));
            
            foreach (var Iteration in types)
            {
                for (int i = 0; i < Iteration.Item1.Length; i++)
                {
                    Console.WriteLine($"{Iteration.Item3[i]} {Iteration.Item1[i]} = {Iteration.Item2[i]}");
                }
            }
        }
        
        private List<(string[], string[], string[])> GetClassPropertyInfo(object Class, Type _Class)
        {
            var @return = new List<(string[], string[], string[])>();
            
            List<string> propertyNames = new List<string>();
            List<string> propertyTypes = new List<string>();
            List<string> propertyValues = new List<string>();
            
            // https://stackoverflow.com/questions/737151/how-to-get-the-list-of-properties-of-a-class
            foreach (var prop in Class.GetType().GetProperties())
            {
                propertyNames.Add(Convert.ToString(prop.Name));
                propertyValues.Add(Convert.ToString(prop.GetValue(Class, null)));
            }
            
            // System.Reflection.FieldInfo
            // See: https://learn.microsoft.com/en-us/dotnet/api/system.reflection.fieldinfo?view=net-7.0
            FieldInfo[] fi = _Class.GetFields(BindingFlags.NonPublic | BindingFlags.Instance
            | BindingFlags.Public);
            
            for (int i = 0; i < fi.Length; i++)
                propertyTypes.Add(Convert.ToString(fi[i].FieldType));
                
            @return.Add((propertyNames.ToArray(), propertyValues.ToArray(), propertyTypes.ToArray()));
            
            return @return;
        }
    }
}

它可以工作,但当数组是属性时就不行了。
最好的问候,
-winscripter。

tzdcorbm

tzdcorbm1#

下面将获取每个属性的名称、类型和值(作为字符串)-您可以将其作为起点。然后,您可以将名称、类型和值存储在所需的任何结构中并返回。希望能帮上忙。

using System;
using System.Collections;
using System.Reflection;

class Animal
{
    public string AnimalName { get; set; }
    public string AnimalType { get; set; }
    public int AnimalAgeInMonths { get; set; }
    public int[] array { get; set; } 
}

class Program
{
    static void Main()
    {

        Animal animal = new Animal();
        animal.AnimalName = null; // No name yet
        animal.AnimalType = "Sheep";
        animal.AnimalAgeInMonths = 7;
        animal.array = new int[] { 1, 3, 5, 7, 9 };
        
        class_info( animal );
            
    }
    
    static void class_info(object Class)
    {
        String val;
        
        foreach (PropertyInfo propertyInfo in Class.GetType().GetProperties())
        {
            // Property Name ...
            Console.WriteLine( propertyInfo.Name );

            // Property type (as string) ...
            Console.WriteLine( propertyInfo.PropertyType.ToString() );

            // Property value (as string) ...
            if ( propertyInfo.GetValue(Class, null) is null ) 
            {
                val = "null";
                Console.WriteLine( val );
            }
            else
            {
                // Property is an array, show values (as strings) ...
                if (propertyInfo.PropertyType.IsArray)
                {

                    IEnumerable array = propertyInfo.GetValue( Class, null ) as IEnumerable;

                    if ( array is null )
                    {
                        Console.WriteLine( "Array is null" );
                    }
                    else
                    {
                        Console.WriteLine("Array values");
                        Console.WriteLine("------------");

                        foreach (var element in array)
                            Console.WriteLine(element.ToString());
                    }

                }
                else
                {
                   val = propertyInfo.GetValue(Class, null).ToString();
                   Console.WriteLine( val );
                }
            }

        }  
        
    }
    
}
5f0d552i

5f0d552i2#

看起来你只需要3个数组。这些都可以通过Reflection API轻松获得。

static (string[], string?[], string[]) GetClassPropertyInfo(object o) {
    // pass binding flags here if you want a different set of properties than default behaviour
    var properties = o.GetType().GetProperties();
    return (
        properties.Select(x => x.Name).ToArray(),
        properties.Select(x => x.GetValue(o)?.ToString()).ToArray(),
        properties.Select(x => x.PropertyType.Name).ToArray()
    );
}

关于第二个数组-您需要一种方法来将任何属性值(包括null)转换为string。这里我调用了ToString,如果值是null,结果也是null。这就是为什么第二个数组具有可空元素,并且类型为string?[]
对于第三个数组,Name返回简单的名称,没有命名空间。如果你需要,你可能想做x.PropertyType.FullName ?? x.PropertyType.Name,或者只做x.PropertyType.ToString()
另外请注意,你完全可以在tuple中返回3个东西,就像我在这里所做的那样,而不需要把它们放在列表中。
也就是说,我建议为此创建一个record类型:

record ObjectInfo(string[] Name, string?[] Values, string[] Types);

你会写:

return new ObjectInfo(
    ...
);

同时考虑到它们不应该都是字符串。我觉得这样更有意义:

record ObjectInfo(string[] Name, object?[] Values, Type[] Types);

相关问题