列出<propertyinfo>,但List <propertyinfo>不工作

时间:2017-03-01 14:51:35

标签: c# entity-framework

我正在制作一个辅助方法,它会自动将随机值设置为给定实体(类)的属性,这样我就不必在测试时用值填充每个属性。

在我的例子中,每个实体都继承自BaseEntity类,该类具有ID,CreatedBy,CreatedOn等属性。基本上这个类具有在所有实体之间共享的所有属性。

我在这里要完成的是将独特属性与常用属性分开。

这是我的代码:

public static TEntity PopulateProperties<TEntity>(TEntity entity)
{
    try
    {
        // Since every entity inherits from EntityBase, there is no need to populate properties that are in EntityBase class
        // because the Core project populates them.
        // First of all, we need to get all the properties of EntityBase
        // and then exlude them from the list of properties we will automatically populate

        // Get all properties of EntityBase
        EntityBase entityBase = new EntityBase();
        List<PropertyInfo> entityBaseProperties = new List<PropertyInfo>();
        foreach (var property in entityBase.GetType().GetProperties())
        {
            entityBaseProperties.Add(property);
        }

        // Get all properties of our entity
        List<PropertyInfo> ourEntityProperties = new List<PropertyInfo>();
        foreach (var property in entity.GetType().GetProperties())
        {
            ourEntityProperties.Add(property);
        }

        // Get only the properties related to our entity
        var propertiesToPopulate = ourEntityProperties.Except(entityBaseProperties).ToList();

        // Now we can loop throught the properties and set values to each property
        foreach (var property in propertiesToPopulate)
        {
            // Switch statement can't be used in this case, so we will use the if clause                  
            if (property.PropertyType == typeof(string))
            {
                property.SetValue(entity, "GeneratedString");
            }
            else if (property.PropertyType == typeof(int))
            {
                property.SetValue(entity, 1994);
            }
        }

        return entity;
    }
    finally
    {
    }
} 

问题在于var propertiesToPopulate = entityBaseProperties.Except(ourEntityProperties).ToList();

我所期待的是PropertyInfo对象的列表,这些对象仅对此实体是唯一的,但是我总是获得我的实体的所有属性。 此行不会按预期过滤列表。

任何帮助为什么??

4 个答案:

答案 0 :(得分:3)

PropertyInfo“知道”你曾经问过哪种类型。例如:

using System;
using System.Reflection;

class Base
{
    public int Foo { get; set; }
}

class Child : Base
{    
}

class Test
{
    static void Main()
    {
        var baseProp = typeof(Base).GetProperty("Foo");
        var childProp = typeof(Child).GetProperty("Foo");
        Console.WriteLine(baseProp.Equals(childProp));
        Console.WriteLine(baseProp.ReflectedType);
        Console.WriteLine(childProp.ReflectedType);
    }
}

的输出为:

False
Base
Child

幸运的是,你可以更简单地做到这一点 - 如果你只想知道在TEntity中宣布了哪些属性,你可以使用:

var props = typeof(entity.GetType()).GetProperties(BindingFlags.Instance | 
                                                   BindingFlags.Public | 
                                                   BindingFlags.DeclaredOnly);

调整是否还需要静态属性。重点是BindingFlags.DeclaredOnly

答案 1 :(得分:1)

另一种可能性是检查你的for循环DeclaringType是否与entity的类型相同:

// Get all properties of our entity
List<PropertyInfo> ourEntityProperties = new List<PropertyInfo>();
foreach (var property in entity.GetType().GetProperties())
{
    // check whether it only belongs to the child
    if (property.DeclaringType.Equals(entity.GetType())) 
    {
        ourEntityProperties.Add(property);
    }       
}

然后你只需要一个循环来过滤掉所有必要的属性。

在&#34; linqish&#34; oneliner你可以把它写成:

List<PropertyInfo> ourEntityProperties = entity.GetType().GetProperties().Where(x=>x.DeclaringType.Equals(entity.GetType())).ToList();

但它看起来很可怕;)

答案 2 :(得分:0)

PropertyInfo 包含许多属性,其中一些属性对于它们引用的对象类型具有唯一值,因此我相信您可能只想检查属性的名称属性:

//properties whose names are unique to our Entity
var propertiesToPopulate = ourEntityProperties
    .Where(oep => !entityBaseProperties.Any(ebp => ebp.Name == oep.Name)).ToList();

答案 3 :(得分:0)

我已经创建了一个可以用于这个问题的类

public class DTOGeneratorRule
    {
        #region Members

        protected Random _random;

        protected readonly Dictionary<Type, Func<object>> typeToRandomizerFuncMap = new Dictionary<Type, Func<object>>
        {
        };

        #endregion

        #region Constructors

        public DTOGeneratorRule()
        {
            // Do Not Change this
            // This is explicitly set to assure that values are generated the same for each test
            _random = new Random(123); 

            typeToRandomizerFuncMap.Add(typeof(int), () => _random.Next());
            typeToRandomizerFuncMap.Add(typeof(bool), () => _random.Next() % 2 == 0);
            // Most codes on our system have a limit of 10, this should be fixed when configuration exits
            typeToRandomizerFuncMap.Add(typeof(Guid), () => Guid.NewGuid());
            typeToRandomizerFuncMap.Add(typeof(string), () => _random.GetRandomAlphanumericCode(10));
            //Most of the times we need to work with dates anyway so truncate the time
            typeToRandomizerFuncMap.Add(typeof(DateTime), () =>  DateTime.Now.Date);
            typeToRandomizerFuncMap.Add(typeof(Char), () =>_random.GetRandomAlphanumericCode(1)[0]);
            typeToRandomizerFuncMap.Add(typeof(Double), () => _random.NextDouble());
            typeToRandomizerFuncMap.Add(typeof(float), () => _random.NextFloat());
            typeToRandomizerFuncMap.Add(typeof(Decimal), () => _random.NextDecimal());
        }

        #endregion

        #region Public Methods

        public T SetAutoGeneratedDTOValues<T>(IEnumerable<Action<T>> explicitValueSetters = null, Dictionary<string, Type> typeCaster = null)
            where T : new()
        {
            T initialDTO = new T();
            return this.SetAutoGeneratedDTOValues<T>(initialDTO, explicitValueSetters, typeCaster);
        }

        public T SetAutoGeneratedDTOValues<T>(T initialDTO, IEnumerable<Action<T>> explicitValueSetters = null, Dictionary<string, Type> typeCaster = null)
        {
            if (null == initialDTO)
            {
                throw new ArgumentNullException(nameof(initialDTO));
            }

            //TODO: This needs to work with Members as well
            foreach (var property in typeof (T).GetProperties())
            {
                if (null == property.GetSetMethod())
                {
                    continue;
                }

                object value = null;

                Type propertyType = property.PropertyType;
                if (propertyType.IsGenericType && propertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    propertyType = Nullable.GetUnderlyingType(propertyType);
                }

                var targetType = propertyType;
                if (typeCaster != null && typeCaster.ContainsKey(property.Name))
                {
                    targetType = typeCaster.Get(property.Name);
                }

                value = this.GetRandomValue(targetType);
                value = this.convertToType(value, propertyType);

                property.SetValue(initialDTO, value);
            }

            if (null != explicitValueSetters)
            {
                foreach (var setter in explicitValueSetters)
                {
                    setter.Invoke(initialDTO);
                }
            }

            return initialDTO;
        }

        #endregion

        #region Protected Methods

        protected object convertToType(object value, Type type)
        {
            return Convert.ChangeType(value, type);
        }

        protected bool TryGetRandomValue(Type type, out object value)
        {
            Func<object> getValueFunc;
            if (type.IsEnum)
            {
                var values = Enum.GetValues(type);
                int index = _random.Next(0, values.Length);
                value = values.GetValue(index);
                return true;
            }

            if (typeToRandomizerFuncMap.TryGetValue(type, out getValueFunc))
            {
                value = getValueFunc();
                return true;
            }

            value = null;
            return false;
        }

        protected object GetRandomValue(Type type)
        {
            object value = null;
            Func<object> getValueFunc;
            if (type.IsEnum)
            {
                var values = Enum.GetValues(type);
                int index = _random.Next(0, values.Length);
                value = values.GetValue(index);
            }
            else if (typeToRandomizerFuncMap.TryGetValue(type, out getValueFunc))
            {
                value = getValueFunc();
            }
            else
            {
                value = this.getDefault(type);
            }

            return value;
        }

        protected object getDefault(Type type)
        {
            if (type.IsValueType)
            {
                return Activator.CreateInstance(type);
            }
            return null;
        }

        #endregion

    }

您还需要一些静态扩展

public static class RandomExtensions
{
    public static decimal NextDecimal(this Random rng)
    {
        // The max value should not be too large to avoid out of range errors when saving to database.
        return Math.Round(rng.NextDecimal(10000, 25), 2);
    }

    //From Another Jon Skeet: http://stackoverflow.com/a/3365374/1938988 
    public static float NextFloat(this Random rng)
    {
        // Perform arithmetic in double type to avoid overflowing
        double range = (double)float.MaxValue - (double)float.MinValue;
        double sample = rng.NextDouble();
        double scaled = (sample * range) + float.MinValue;
        return (float)scaled;
    }

    public static string GetRandomAlphanumericCode(this Random random, int length)
    {
      string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
      return RandomExtensions.GetRandomString(random, length, chars);
    }
}