Десятичная точность и масштаб в EF Code First


230

Я экспериментирую с этим первым подходом к коду, но теперь выясняю, что свойство типа System.Decimal отображается на столбец sql типа decimal (18, 0).

Как мне установить точность столбца базы данных?


11
Одним из способов является использование [Column(TypeName = "decimal(18,4)")]атрибута для ваших десятичных свойств
S.Serpooshan

[Column (TypeName = "decimal (18,4)")] работал отлично !!!
Брайан Райс

Ответы:


257

Ответ от Дейва Ван ден Эйнде сейчас устарел. Есть 2 важных изменения, начиная с EF 4.1 и далее, класс ModelBuilder теперь называется DbModelBuilder, и теперь существует метод DecimalPropertyConfiguration.HasPrecision, имеющий сигнатуру:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

где точность - это общее количество цифр, которые будет хранить БД, независимо от того, где находится десятичная точка, а шкала - это количество десятичных знаков, которые она будет хранить.

Поэтому нет необходимости перебирать свойства, как показано, но их можно просто вызвать из

public class EFDbContext : DbContext
{
   protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
   {
       modelBuilder.Entity<Class>().Property(object => object.property).HasPrecision(12, 10);

       base.OnModelCreating(modelBuilder);
   }
}

Для тех, кто испытывает проблемы с DbModelBuilder, попробуйтеSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Ллойд Пауэлл

1
Я заметил, что ты никогда не звонил base.OnModelCreating(modelBuilder);. Было ли это намеренно или просто жертвой ввода кода онлайн вместо IDE?
BenSwayne

1
@BenSwayne спасибо за место, это мое упущение, а не что-то преднамеренное. Я отредактирую ответ.
AlexC

27
2 аргумента HasPrecision (точность, масштаб) плохо документированы. точность - это общее количество цифр, которые оно будет хранить, независимо от того, где находится десятичная точка. шкала - это количество десятичных разрядов, которые оно будет хранить.
Крис Москини

1
Существует ли конфигурация EF для установки всех десятичных свойств всех объектов в одном месте? Мы обычно используем (19,4). Было бы хорошо, чтобы это автоматически применялось ко всем десятичным свойствам, поэтому мы не можем забыть установить точность свойства и упустить ожидаемую точность в вычислениях.
Майк де Клерк

89

Если вы хотите установить точность для всех decimalsв EF6, вы можете заменить DecimalPropertyConventionсоглашение по умолчанию, используемое в DbModelBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(38, 18));
}

Значение по умолчанию DecimalPropertyConventionв EF6 отображает decimalсвойства в decimal(18,2)столбцы.

Если вы хотите, чтобы отдельные свойства имели указанную точность, вы можете установить точность для свойства объекта в DbModelBuilder:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Entity<MyEntity>().Property(e => e.Value).HasPrecision(38, 18);
}

Или добавьте EntityTypeConfiguration<>для объекта, который указывает точность:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Configurations.Add(new MyEntityConfiguration());
}

internal class MyEntityConfiguration : EntityTypeConfiguration<MyEntity>
{
    internal MyEntityConfiguration()
    {
        this.Property(e => e.Value).HasPrecision(38, 18);
    }
}

1
Мое любимое решение. Прекрасно работает при использовании CodeFirst и миграций: EF ищет все свойства во всех классах, где используется «десятичное число», и генерирует миграцию для этих свойств. Большой!
хорошо

75

Я хорошо провел время, создавая собственный атрибут для этого:

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
    public DecimalPrecisionAttribute(byte precision, byte scale)
    {
        Precision = precision;
        Scale = scale;

    }

    public byte Precision { get; set; }
    public byte Scale { get; set; }

}

используя это так

[DecimalPrecision(20,10)]
public Nullable<decimal> DeliveryPrice { get; set; }

и магия происходит при создании модели с некоторым отражением

protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
    foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
                                   where t.IsClass && t.Namespace == "YOURMODELNAMESPACE"
                                   select t)
     {
         foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
                p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
         {

             var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
             ParameterExpression param = ParameterExpression.Parameter(classType, "c");
             Expression property = Expression.Property(param, propAttr.prop.Name);
             LambdaExpression lambdaExpression = Expression.Lambda(property, true,
                                                                      new ParameterExpression[]
                                                                          {param});
             DecimalPropertyConfiguration decimalConfig;
             if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
             {
                 MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[7];
                 decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
             }
             else
             {
                 MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[6];
                 decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
             }

             decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
        }
    }
}

первая часть - получить все классы в модели (в этой сборке определен мой пользовательский атрибут, поэтому я использовал его для получения сборки с моделью)

второй foreach получает все свойства в этом классе с помощью пользовательского атрибута и самого атрибута, чтобы я мог получить данные о точности и масштабе

после этого мне нужно позвонить

modelBuilder.Entity<MODEL_CLASS>().Property(c=> c.PROPERTY_NAME).HasPrecision(PRECISION,SCALE);

поэтому я вызываю modelBuilder.Entity () с помощью отражения и сохраняю его в переменной entityConfig, затем строю лямбда-выражение "c => c.PROPERTY_NAME"

После этого, если десятичная дробь обнуляется, я называю

Property(Expression<Func<TStructuralType, decimal?>> propertyExpression) 

метод (я называю это положением в массиве, это не идеально, я знаю, любая помощь будет высоко ценится)

и если это не обнуляемо, я называю

Property(Expression<Func<TStructuralType, decimal>> propertyExpression)

метод.

Имея DecimalPropertyConfiguration, я вызываю метод HasPrecision.


3
Спасибо за это. Это спасло меня от создания тысяч лямбда-выражений.
Шон

1
Это прекрасно работает, и очень чисто! Для EF 5 я изменил System.Data.Entity.ModelConfiguration.ModelBuilder на System.Data.Entity.DbModelBuilder
Колин

3
Я использую, MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });чтобы получить правильную перегрузку. кажется, работает до сих пор.
fscan

3
Я обернул это в библиотеку и упростил вызов из DbContext: github.com/richardlawley/EntityFrameworkAttributeConfig (также доступен через nuget)
Ричард

Ричард, мне нравится идея вашего проекта, но есть ли в нем что-то, что требует EF6? Я бы использовал его, если бы была EF5-совместимая версия, чтобы я мог использовать ее с моей версией ODP.NET.
Патрик Салапски

50

Используя команду DecimalPrecisonAttributefrom KinSlayerUY, в EF6 вы можете создать соглашение, которое будет обрабатывать отдельные свойства, которые имеют атрибут (в отличие от установки DecimalPropertyConventionподобного в этом ответе, который повлияет на все десятичные свойства).

[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
public sealed class DecimalPrecisionAttribute : Attribute
{
    public DecimalPrecisionAttribute(byte precision, byte scale)
    {
        Precision = precision;
        Scale = scale;
    }
    public byte Precision { get; set; }
    public byte Scale { get; set; }
}

public class DecimalPrecisionAttributeConvention
    : PrimitivePropertyAttributeConfigurationConvention<DecimalPrecisionAttribute>
{
    public override void Apply(ConventionPrimitivePropertyConfiguration configuration, DecimalPrecisionAttribute attribute)
    {
        if (attribute.Precision < 1 || attribute.Precision > 38)
        {
            throw new InvalidOperationException("Precision must be between 1 and 38.");
        }

        if (attribute.Scale > attribute.Precision)
        {
            throw new InvalidOperationException("Scale must be between 0 and the Precision value.");
        }

        configuration.HasPrecision(attribute.Precision, attribute.Scale);
    }
}

Тогда в вашем DbContext:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new DecimalPrecisionAttributeConvention());
}

@MichaelEdenfield На самом деле нет, в EF6 такого нет. Поэтому я добавил два ответа, один и другой, на который вы ссылались. Это атрибут, который можно присвоить одному десятичному свойству, а не влиять на все десятичные свойства в модели.
kjbartel


1
Если вы собираетесь проверить границы Precision, то я рекомендую установить верхнюю границу на 28 (то есть > 28в вашем состоянии). Согласно документации MSDN, System.Decimalточность может составлять не более 28-29 цифр ( msdn.microsoft.com/en-us/library/364x0z75.aspx ). Кроме того, атрибут объявляется Scaleкак byte, что означает, что ваше предварительное условие attribute.Scale < 0не требуется.
NathanAldenSr

2
@kjbartel Это правда, что некоторые поставщики баз данных поддерживают точность больше 28; однако, согласно MSDN, System.Decimalнет. Поэтому нет смысла устанавливать верхнее предусловие на значение больше 28; System.Decimalпо-видимому, не может представлять такие большие числа. Также помните, что этот атрибут полезен для поставщиков данных, отличных от SQL Server. Например, numericтип PostgreSQL поддерживает до 131072 цифр точности.
NathanAldenSr

1
@NathanAldenSr Как я уже сказал, базы данных используют десятичную систему с фиксированной запятой ( msdn ), тогда как System.Decimal является плавающей запятой . Они совершенно разные. Например, наличие decimal(38,9)столбца будет счастливым, System.Decimal.MaxValueно decimal(28,9)столбец - нет. Нет оснований ограничивать точность только до 28.
kjbartel

47

По-видимому, вы можете переопределить метод DbContext.OnModelCreating () и настроить точность следующим образом:

protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Product>().Property(product => product.Price).Precision = 10;
    modelBuilder.Entity<Product>().Property(product => product.Price).Scale = 2;
}

Но это довольно утомительный код, когда вам нужно сделать это со всеми вашими ценовыми свойствами, поэтому я придумал это:

    protected override void OnModelCreating(System.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder)
    {
        var properties = new[]
        {
            modelBuilder.Entity<Product>().Property(product => product.Price),
            modelBuilder.Entity<Order>().Property(order => order.OrderTotal),
            modelBuilder.Entity<OrderDetail>().Property(detail => detail.Total),
            modelBuilder.Entity<Option>().Property(option => option.Price)
        };

        properties.ToList().ForEach(property =>
        {
            property.Precision = 10;
            property.Scale = 2;
        });

        base.OnModelCreating(modelBuilder);
    }

Рекомендуется вызывать базовый метод при переопределении метода, даже если базовая реализация ничего не делает.

Обновление: эта статья также была очень полезной.


10
Спасибо, это указало мне в правильном направлении. В CTP5 синтаксис был изменен, чтобы разрешить добавление точности и масштаба в одном выражении: modelBuilder.Entity <Product> (). Property (product => product.Price) .HasPrecision (6, 2);
полковник

2
Тем не менее, было бы неплохо иметь какое-то «значение по умолчанию», которое вы могли бы установить для всех десятичных дробей?
Дэйв Ван ден Эйнд

3
Я не думаю, что звонить base.OnModelCreating(modelBuilder);необходимо. Из метаданных DbContext в VS: The default implementation of this method does nothing, but it can be overridden in a derived class such that the model can be further configured before it is locked down.
Мэтт Дженкинс

@Matt: Это хорошо, но как разработчик, я не должен заботиться об этом и всегда вызывать базу.
Дейв Ван ден Эйнде

@ Дэйв и @Matt: Был комментарий, что это было «ВАЖНО», чтобы позвонить базе. Это хорошая практика, но когда источник EF имеет пустую реализацию, вводить в заблуждение утверждение, что это важно, вводит в заблуждение. Это заставляет людей задуматься о том, что делает база. Мне было так любопытно, что ВАЖНО, я декомпилировал в ef5.0 для проверки. Здесь пусто. Так что просто хорошая привычка.
Фил Соади

30

В Entity Framework версии 6 (Alpha, rc1) есть нечто, называемое пользовательскими соглашениями . Чтобы установить десятичную точность:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Properties<decimal>().Configure(config => config.HasPrecision(18, 4));
}

Ссылка:


22
[Column(TypeName = "decimal(18,2)")]

это будет работать с первыми миграциями кода EF Core, как описано здесь .


1
Если вы просто добавите это в свою модель, вы можете получитьThe store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage

@Savage выглядит так, как будто это проблема вашего провайдера базы данных или версии базы данных
Elnoor

@Elnoor Savage верен, это приведет к ошибке в EF Migrations 6.x. Устаревшая неосновная версия не поддерживает указание точности / масштаба через атрибут Column и ничего не делает (по умолчанию 18,2), если вы используете атрибут DataType. Чтобы заставить его работать через Attribute в EF 6.x, вам нужно реализовать собственное расширение для ModelBuilder.
Крис Москини

1
@ChrisMoschini, я изменил свой ответ, упомянув EF Core. Спасибо
Elnoor

14

эта строка кода может быть более простым способом сделать то же самое:

 public class ProductConfiguration : EntityTypeConfiguration<Product>
    {
        public ProductConfiguration()
        {
            this.Property(m => m.Price).HasPrecision(10, 2);
        }
    }

9

- ДЛЯ EF CORE - с использованием System.ComponentModel.DataAnnotations;

использовать [Column( TypeName = "decimal( точность , масштаб )")]

Точность = общее количество используемых символов

Масштаб = общее число после точки. (легко запутаться)

Пример :

public class Blog
{
    public int BlogId { get; set; }
    [Column(TypeName = "varchar(200)")]
    public string Url { get; set; }
    [Column(TypeName = "decimal(5, 2)")]
    public decimal Rating { get; set; }
}

Более подробная информация здесь: https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types


3

В EF6

modelBuilder.Properties()
    .Where(x => x.GetCustomAttributes(false).OfType<DecimalPrecisionAttribute>().Any())
    .Configure(c => {
        var attr = (DecimalPrecisionAttribute)c.ClrPropertyInfo.GetCustomAttributes(typeof (DecimalPrecisionAttribute), true).FirstOrDefault();

        c.HasPrecision(attr.Precision, attr.Scale);
    });

Этот ответ, кажется, является обновлением до другого ответа, который определяет атрибут, вы должны отредактировать его в этом ответе
Рис Бевилаква

3

Вы всегда можете сказать EF сделать это с соглашениями в классе Context в функции OnModelCreating следующим образом:

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    // <... other configurations ...>
    // modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
    // modelBuilder.Conventions.Remove<ManyToManyCascadeDeleteConvention>();
    // modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();

    // Configure Decimal to always have a precision of 18 and a scale of 4
    modelBuilder.Conventions.Remove<DecimalPropertyConvention>();
    modelBuilder.Conventions.Add(new DecimalPropertyConvention(18, 4));

    base.OnModelCreating(modelBuilder);
}

Это относится только к FY Code First EF и относится ко всем десятичным типам, отображаемым в БД.


Это не работает, пока не Remove<DecimalPropertyConvention>();наступит раньше Add(new DecimalPropertyConvention(18, 4));. Я думаю, что это странно, что не просто автоматически переопределяется.
Майк де Клерк

2

С помощью

System.ComponentModel.DataAnnotations;

Вы можете просто вставить этот атрибут в вашу модель:

[DataType("decimal(18,5)")]

1
это самая простая реализация для удобства чтения и простоты. ИМХО
ранцемс

11
Согласно msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx , этот ответ фактически неверен. «Не путайте атрибут TypeName столбца с DataType DataAnnotation. DataType - это аннотация, используемая для пользовательского интерфейса, которая игнорируется Code First».
speckledcarp

2
@ransems Я тоже так думал, пока я только что проверил это и, как было сказано выше, это не работает для CodeFirst и не переносится в базу данных
RoLYroLLs

1

Вы можете найти больше информации о MSDN - аспекте Entity Data Model. http://msdn.microsoft.com/en-us/library/ee382834.aspx Полный рекомендуется.


Это здорово и все, но как это относится к Code-First?
Дэйв Ван ден Эйнд

Это полезно, но я не могу указать атрибут [Precision] для десятичного числа. Поэтому я использовал решение, предоставленное @KinSlayerUY.
Колин

1

Актуально для EntityFrameworkCore 3.1.3:

какое-то решение в OnModelCreating:

var fixDecimalDatas = new List<Tuple<Type, Type, string>>();
foreach (var entityType in builder.Model.GetEntityTypes())
{
    foreach (var property in entityType.GetProperties())
    {
        if (Type.GetTypeCode(property.ClrType) == TypeCode.Decimal)
        {
            fixDecimalDatas.Add(new Tuple<Type, Type, string>(entityType.ClrType, property.ClrType, property.GetColumnName()));
        }
    }
}

foreach (var item in fixDecimalDatas)
{
    builder.Entity(item.Item1).Property(item.Item2, item.Item3).HasColumnType("decimal(18,4)");
}

//custom decimal nullable:
builder.Entity<SomePerfectEntity>().Property(x => x.IsBeautiful).HasColumnType("decimal(18,4)");

0

Пользовательский атрибут KinSlayerUY работал хорошо для меня, но у меня были проблемы с ComplexTypes. Они отображались как сущности в коде атрибута, поэтому их нельзя было сопоставить как ComplexType.

Поэтому я расширил код, чтобы учесть это:

public static void OnModelCreating(DbModelBuilder modelBuilder)
    {
        foreach (Type classType in from t in Assembly.GetAssembly(typeof(DecimalPrecisionAttribute)).GetTypes()
                                   where t.IsClass && t.Namespace == "FA.f1rstval.Data"
                                   select t)
        {
            foreach (var propAttr in classType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.GetCustomAttribute<DecimalPrecisionAttribute>() != null).Select(
                   p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) }))
            {

                ParameterExpression param = ParameterExpression.Parameter(classType, "c");
                Expression property = Expression.Property(param, propAttr.prop.Name);
                LambdaExpression lambdaExpression = Expression.Lambda(property, true,
                                                                         new ParameterExpression[] { param });
                DecimalPropertyConfiguration decimalConfig;
                int MethodNum;
                if (propAttr.prop.PropertyType.IsGenericType && propAttr.prop.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
                {
                    MethodNum = 7;
                }
                else
                {
                    MethodNum = 6;
                }

                //check if complextype
                if (classType.GetCustomAttribute<ComplexTypeAttribute>() != null)
                {
                    var complexConfig = modelBuilder.GetType().GetMethod("ComplexType").MakeGenericMethod(classType).Invoke(modelBuilder, null);
                    MethodInfo methodInfo = complexConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
                    decimalConfig = methodInfo.Invoke(complexConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
                }
                else
                {
                    var entityConfig = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(classType).Invoke(modelBuilder, null);
                    MethodInfo methodInfo = entityConfig.GetType().GetMethods().Where(p => p.Name == "Property").ToList()[MethodNum];
                    decimalConfig = methodInfo.Invoke(entityConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;
                }

                decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
            }
        }
    }

0

@ Mark007, я изменил критерии выбора типа, чтобы использовать свойства DbSet <> DbContext. Я думаю, что это безопаснее, потому что бывают случаи, когда в данном пространстве имен есть классы, которые не должны быть частью определения модели или они не являются сущностями. Или ваши сущности могут находиться в отдельных пространствах имен или отдельных сборках и объединяться в единый контекст.

Кроме того, хотя это маловероятно, я не думаю, что можно полагаться на порядок определений методов, поэтому лучше их извлекать с помощью списка параметров. (.GetTypeMethods () - это метод расширения, который я построил для работы с новой парадигмой TypeInfo и может сгладить иерархию классов при поиске методов).

Обратите внимание, что OnModelCreating делегирует этот метод:

    private void OnModelCreatingSetDecimalPrecisionFromAttribute(DbModelBuilder modelBuilder)
    {
        foreach (var iSetProp in this.GetType().GetTypeProperties(true))
        {
            if (iSetProp.PropertyType.IsGenericType
                    && (iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(IDbSet<>) || iSetProp.PropertyType.GetGenericTypeDefinition() == typeof(DbSet<>)))
            {
                var entityType = iSetProp.PropertyType.GetGenericArguments()[0];

                foreach (var propAttr in entityType
                                        .GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                        .Select(p => new { prop = p, attr = p.GetCustomAttribute<DecimalPrecisionAttribute>(true) })
                                        .Where(propAttr => propAttr.attr != null))
                {
                    var entityTypeConfigMethod = modelBuilder.GetType().GetTypeInfo().DeclaredMethods.First(m => m.Name == "Entity");
                    var entityTypeConfig = entityTypeConfigMethod.MakeGenericMethod(entityType).Invoke(modelBuilder, null);

                    var param = ParameterExpression.Parameter(entityType, "c");
                    var lambdaExpression = Expression.Lambda(Expression.Property(param, propAttr.prop.Name), true, new ParameterExpression[] { param });

                    var propertyConfigMethod =
                        entityTypeConfig.GetType()
                            .GetTypeMethods(true, false)
                            .First(m =>
                            {
                                if (m.Name != "Property")
                                    return false;

                                var methodParams = m.GetParameters();

                                return methodParams.Length == 1 && methodParams[0].ParameterType == lambdaExpression.GetType();
                            }
                            );

                    var decimalConfig = propertyConfigMethod.Invoke(entityTypeConfig, new[] { lambdaExpression }) as DecimalPropertyConfiguration;

                    decimalConfig.HasPrecision(propAttr.attr.Precision, propAttr.attr.Scale);
                }
            }
        }
    }



    public static IEnumerable<MethodInfo> GetTypeMethods(this Type typeToQuery, bool flattenHierarchy, bool? staticMembers)
    {
        var typeInfo = typeToQuery.GetTypeInfo();

        foreach (var iField in typeInfo.DeclaredMethods.Where(fi => staticMembers == null || fi.IsStatic == staticMembers))
            yield return iField;

        //this bit is just for StaticFields so we pass flag to flattenHierarchy and for the purpose of recursion, restrictStatic = false
        if (flattenHierarchy == true)
        {
            var baseType = typeInfo.BaseType;

            if ((baseType != null) && (baseType != typeof(object)))
            {
                foreach (var iField in baseType.GetTypeMethods(true, staticMembers))
                    yield return iField;
            }
        }
    }

Я просто понял, что не имею дело с ComplexTypes таким подходом. Буду пересматривать это позже.
Эниола

Однако решение, предложенное Брайаном , простое, элегантное и работает. Я не буду делать категорических заявлений о производительности, но использование уже отраженного PropertyInfo, а не поиск вашей, должно привести к лучшей производительности на очень больших моделях (порядка 200 и выше).
Эниола
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.