Precisione e scala decimali nel codice EF Primo


230

Sto sperimentando questo approccio basato sul codice, ma ora scopro che una proprietà di tipo System.Decimal viene mappata su una colonna sql di tipo decimale (18, 0).

Come posso impostare la precisione della colonna del database?


11
un modo è usare l' [Column(TypeName = "decimal(18,4)")]attributo per le proprietà decimali
S.Serpooshan

[Column (TypeName = "decimal (18,4)")] ha funzionato benissimo !!!
Brian Rice,

Risposte:


257

La risposta di Dave Van den Eynde non è più aggiornata. Ci sono 2 importanti cambiamenti, da EF 4.1 in poi la classe ModelBuilder è ora DbModelBuilder e ora esiste un metodo DecimalPropertyConfiguration.HasPrecision che ha una firma di:

public DecimalPropertyConfiguration HasPrecision(
byte precision,
byte scale )

dove precisione è il numero totale di cifre che il db memorizzerà, indipendentemente da dove cade il punto decimale e la scala è il numero di posizioni decimali che memorizzerà.

Pertanto non è necessario scorrere le proprietà come mostrato, ma è possibile richiamare semplicemente

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);
   }
}

Per chiunque abbia problemi con DbModelBuilder, provaSystem.Data.Entity.ModelConfiguration.ModelBuilder modelBuilder
Lloyd Powell,

1
Ho notato che non hai mai chiamato base.OnModelCreating(modelBuilder);. Era intenzionale o era solo una vittima della digitazione del codice online anziché in un IDE?
BenSwayne,

1
@BenSwayne grazie per lo spot, questa è la mia omissione, non nulla di intenzionale. Modificherò la risposta.
AlexC

26
I 2 argomenti di HasPrecision (precisione, scala) sono scarsamente documentati. precisione è il numero totale di cifre che memorizzerà, indipendentemente da dove cade il punto decimale. scala è il numero di posizioni decimali che memorizzerà.
Chris Moschini,

1
Esiste una configurazione EF per impostarla per tutte le proprietà decimali su tutte le entità in un unico posto? Usiamo generalmente (19,4). Sarebbe bello avere questo automaticamente applicato a tutte le proprietà decimali, quindi non possiamo dimenticare di impostare una precisione di proprietà e perdere la precisione prevista nei calcoli.
Mike de Klerk,

89

Se vuoi impostare la precisione per tutti decimals in EF6, è possibile sostituire la DecimalPropertyConventionconvenzione predefinita utilizzata in DbModelBuilder:

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

Il predefinito DecimalPropertyConvention in EF6 associa le decimalproprietà alle decimal(18,2)colonne.

Se si desidera solo che le singole proprietà abbiano una precisione specificata, è possibile impostare la precisione per la proprietà dell'entità su DbModelBuilder :

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

Oppure aggiungi un EntityTypeConfiguration<>per l'entità che specifica la precisione:

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
La mia soluzione preferita Funziona perfettamente quando si utilizza CodeFirst e le migrazioni: EF cerca tutte le proprietà in tutte le classi in cui viene utilizzato "decimale" e genera una migrazione per queste proprietà. Grande!
Okieh,

75

Mi sono divertito a creare un attributo personalizzato per questo:

[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; }

}

usandolo in questo modo

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

e la magia accade alla creazione del modello con qualche riflessione

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);
        }
    }
}

la prima parte è quella di ottenere tutte le classi nel modello (il mio attributo personalizzato è definito in quell'assemblaggio, quindi l'ho usato per ottenere l'assemblaggio con il modello)

il secondo foreach ottiene tutte le proprietà in quella classe con l'attributo personalizzato e l'attributo stesso in modo che io possa ottenere la precisione e ridimensionare i dati

dopo che devo chiamare

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

quindi chiamo modelBuilder.Entity () per riflessione e lo memorizzo nella variabile entityConfig, quindi creo l'espressione lambda "c => c.PROPERTY_NAME"

Dopodiché, se il decimale è nullable chiamo il

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

metodo (lo chiamo per posizione nell'array, non è l'ideale lo so, qualsiasi aiuto sarà molto apprezzato)

e se non è nullable chiamo il

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

metodo.

Avendo DecimalPropertyConfiguration chiamo il metodo HasPrecision.


3
Grazie per questo. Mi ha salvato dal generare migliaia di espressioni lambda.
Sean,

1
Funziona benissimo ed è super pulito! Per EF 5, ho cambiato System.Data.Entity.ModelConfiguration.ModelBuilder in System.Data.Entity.DbModelBuilder
Colin

3
io uso MethodInfo methodInfo = entityConfig.GetType().GetMethod("Property", new[] { lambdaExpression.GetType() });per ottenere il sovraccarico corretto. sembra funzionare finora.
fscan

3
L'ho inserito in una libreria e ho semplificato la chiamata dal DbContext: github.com/richardlawley/EntityFrameworkAttributeConfig (disponibile anche tramite nuget)
Richard

Richard, adoro l'idea del tuo progetto ma c'è qualcosa che richiede EF6? Lo userei se esistesse una versione compatibile con EF5, in modo da poterlo utilizzare con la mia versione di ODP.NET.
Patrick Szalapski l'

50

Usando DecimalPrecisonAttributeda KinSlayerUY, in EF6 puoi creare una convenzione che gestirà le singole proprietà che hanno l'attributo (invece di impostare DecimalPropertyConventionsimili in questa risposta che influenzerà tutte le proprietà decimali).

[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);
    }
}

Quindi nel tuo DbContext:

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

@MichaelEdenfield In realtà no, non ce n'è uno in EF6. Ecco perché ho aggiunto due risposte, questa e l'altra a cui hai fatto riferimento. Questo è un attributo che puoi inserire in una singola proprietà decimale anziché influire su tutte le proprietà decimali nel modello.
kjbartel,

mio male, non ho notato che hai scritto entrambi: \
Michael Edenfield

1
Se hai intenzione di controllare i limiti Precision, ti consiglio di impostare il limite superiore su 28 (quindi > 28nelle tue condizioni). Secondo la documentazione MSDN, System.Decimalpuò rappresentare solo un massimo di 28-29 cifre di precisione ( msdn.microsoft.com/en-us/library/364x0z75.aspx ). Inoltre, l'attributo dichiara Scalecome byte, il che significa che il prerequisito attribute.Scale < 0non è necessario.
NathanAldenSr

2
@kjbartel È vero che alcuni provider di database supportano precisioni maggiori di 28; tuttavia, secondo MSDN, System.Decimalno. Pertanto non ha senso impostare il presupposto del limite superiore su qualcosa di più grande di 28; System.Decimalnon può rappresentare numeri così grandi, apparentemente. Inoltre, tenere presente che questo attributo è utile per i fornitori di dati diversi da SQL Server. Ad esempio, il numerictipo di PostgreSQL supporta fino a 131072 cifre di precisione.
NathanAldenSr

1
@NathanAldenSr Come ho detto, i database usano un decimale a virgola fissa ( msdn ) mentre System.Decimal è a virgola mobile . Sono completamente diversi. Ad esempio, avere una decimal(38,9)colonna conterrà felice, System.Decimal.MaxValuema una decimal(28,9)colonna no. Non c'è motivo di limitare la precisione a soli 28.
kjbartel,

47

Apparentemente, puoi sovrascrivere il metodo DbContext.OnModelCreating () e configurare la precisione in questo modo:

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;
}

Ma questo è un codice piuttosto noioso quando devi farlo con tutte le tue proprietà legate al prezzo, quindi ho pensato a questo:

    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);
    }

È buona norma chiamare il metodo di base quando si esegue l'override di un metodo, anche se l'implementazione di base non fa nulla.

Aggiornamento: questo articolo è stato anche molto utile.


10
Grazie, questo mi ha indicato la giusta direzione. In CTP5 la sintassi è cambiata per consentire l'aggiunta di Precisione e Scala nella stessa istruzione: modelBuilder.Entity <Product> () .Property (product => product.Price) .HasPrecision (6, 2);
Col

2
Tuttavia, non sarebbe bello avere una sorta di "default" che potresti impostare per tutti i decimali?
Dave Van den Eynde,

3
Non credo base.OnModelCreating(modelBuilder);sia necessario chiamare . Dai metadati DbContext in 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 Jenkins,

@Matt: È carino, ma come implementatore non dovrei preoccuparmene e chiamare sempre la base.
Dave Van den Eynde,

@ Dave e @Matt: c'era un commento che era "IMPORTANTE" per chiamare base. È buona prassi, ma quando la fonte EF ha un'implementazione vuota, è fuorviante affermare che è importante. Ciò lascia le persone a chiedersi cosa fa la base. Ero così curioso di ciò che era IMPORTANTE che ho decompilato su ef5.0 per verificare. Lì non c'è niente. Quindi solo una buona abitudine.
Phil Soady,


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

questo funzionerà con le prime migrazioni del codice EF Core come descritto qui .


1
Se aggiungi semplicemente questo al tuo modello, puoi ottenereThe store type 'decimal(18,2)' could not be found in the SqlServer provider manifest
Savage

@Savage sembra che sia un problema con il tuo provider di database o con la versione del database
Elnoor

@Elnoor Savage è corretto, questo genererà un errore in EF Migrations 6.x. La versione legacy non Core non supporta la specifica di precisione / scala tramite l'attributo Column e non fa nulla (il valore predefinito è 18,2) se si utilizza l'attributo DataType. Per farlo funzionare tramite Attributo in EF 6.x, è necessario implementare la propria estensione per ModelBuilder.
Chris Moschini,

1
@ChrisMoschini, ho cambiato la mia risposta citando EF Core. Grazie
Elnoor il

14

questa riga di codice potrebbe essere un modo più semplice per realizzare lo stesso:

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

9

- PER EF CORE - con utilizzo di System.ComponentModel.DataAnnotations;

use [Column( TypeName = "decimal( precisione , scala )")]

Precisione = numero totale di caratteri utilizzati

Scala = numero totale dopo il punto. (facile confondersi)

Esempio :

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; }
}

Maggiori dettagli qui: https://docs.microsoft.com/en-us/ef/core/modeling/relational/data-types


3

In 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);
    });

Questa risposta sembra essere un aggiornamento a un'altra risposta che definisce l'attributo, è necessario modificarlo in quella risposta
Rhys Bevilaqua,

3

Puoi sempre dire a EF di farlo con le convenzioni nella classe Context nella funzione OnModelCreating come segue:

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);
}

Questo vale solo per Code First EF fyi e si applica a tutti i tipi decimali mappati sul db.


Non funzionava fino a quando non Remove<DecimalPropertyConvention>();viene prima Add(new DecimalPropertyConvention(18, 4));. Penso che sia strano che non venga automaticamente ignorato.
Mike de Klerk,

2

utilizzando

System.ComponentModel.DataAnnotations;

Puoi semplicemente inserire quell'attributo nel tuo modello:

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

1
questa è l'implementazione più semplice per leggibilità e semplicità. IMHO
riscatta il

11
Per msdn.microsoft.com/en-us/library/jj591583(v=vs.113).aspx , questa risposta è effettivamente errata. "Non confondere l'attributo TypeName di Column con DataType DataAnnotation. DataType è un'annotazione utilizzata per l'interfaccia utente e viene ignorata da Code First."
macchiato di carpe

2
@ransems L'ho pensato anch'io, fino a quando non l'ho appena provato e, come è stato detto sopra, questo non funziona per CodeFirst e non migra nel database
RoLYroLLs


1

Effettivo per EntityFrameworkCore 3.1.3:

qualche soluzione in 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

L'attributo personalizzato di KinSlayerUY ha funzionato bene per me ma ho avuto problemi con ComplexTypes. Erano stati mappati come entità nel codice dell'attributo, quindi non potevano essere mappati come ComplexType.

Ho quindi esteso il codice per consentire ciò:

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, ho modificato i criteri di selezione del tipo per utilizzare le proprietà DbSet <> di DbContext. Penso che sia più sicuro perché ci sono momenti in cui ci sono classi nello spazio dei nomi dato che non dovrebbero far parte della definizione del modello o lo sono ma non sono entità. Oppure le tue entità potrebbero risiedere in spazi dei nomi separati o assiemi separati ed essere riunite in un unico contesto.

Inoltre, anche se è improbabile, non penso che sia sicuro fare affidamento sull'ordinamento delle definizioni dei metodi, quindi è meglio estrarli dall'elenco dei parametri. (.GetTypeMethods () è un metodo di estensione che ho creato per funzionare con il nuovo paradigma TypeInfo e può appiattire le gerarchie di classi quando si cercano metodi).

Si noti che OnModelCreating è delegato a questo metodo:

    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;
            }
        }
    }

Ho appena realizzato di non avere a che fare con ComplexTypes con questo approccio. Lo rivedremo più tardi.
Eniola,

Tuttavia, la soluzione proposta da Brian è semplice, elegante e funzionale. Non farò dichiarazioni categoriche sulle prestazioni, ma cavalcare già PropertyInfo piuttosto che cercare i tuoi dovrebbe produrre prestazioni migliori su modelli molto grandi (nell'ordine di 200 e oltre).
Eniola,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.