6
votes

Comment définir dynamiquement une propriété d'une classe sans utiliser de réflexion (avec dynamique) en C # 4 lorsque le nom de la propriété provient d'une autre source

Je suis en train de construire / mettre à jour une entitéFramework entityObject à l'exécution. Je souhaite définir les propriétés de la classe d'entités, les noms de propriété et les valeurs provenant d'une autre source.

Donc, je le fais; xxx

alors, comment puis-je me débarrasser de "t.geproperty (valeurs [j] .Entitypropertyname) .Setvalue (localéité, valeur, null);" Partie, y a-t-il une façon dynamique de faire cela?

quelque chose comme;

dynamiccastedlocalentyty.getproperty (valeurs [J] .Entitypropertyname) = Valeur;

Merci .


1 commentaires

S'il y a vraiment une telle expression dynamiccastedlocaleentality.geproperty (valeurs [j] .Entityproper Tyname) = valeur; , comment l'exécution peut-elle savoir quelle instance vous souhaitez donner la valeur?


5 Réponses :


1
votes

J'ai bien peur que non. Toute utilisation d'un objet dynamique dynamique est cuit à l'heure de la compilation. Tout appel pouvant varier au moment de l'exécution doit être effectué à l'aide de la réflexion.


0 commentaires

2
votes

éventuellement pas avec entitéObject, mais si vous avez eu un expresoObject que vous pouvez faire

dynamic entity = new ExpandoObject();
(entity as IDictionary<String, Object>)[values[j].EntityPropertyName] = value


0 commentaires

14
votes

Une réponse longue à venir. La réflexion est excellente dans de nombreuses situations, horrible dans certaines mais dans presque tous les cas, c'est lent.

Il y a au moins 4 façons différentes de définir une propriété à .NET sans avoir à utiliser la réflexion. P>

Je pensais Je démontre l'un d'entre eux: utiliser des arbres d'expression compilés. Notez que le bâtiment d'expression est plutôt cher aussi, c'est pourquoi il est très important de mettre en cache le délégué que celui-ci dans un dictionnaire (par exemple): p>

Les arbres d'expression ont été introduits dans .net35 et est utilisé pour beaucoup des choses. Ici, je les utilise pour construire une expression de constructeur de propriétés, puis la compilez dans un délégué. P>

L'exemple démontre une synchronisation différente pour les différents cas, mais voici mes numéros: Cas de contrôle (codé dur): 0,02S Réflexion: 1.78S Arbre d'expression: 0.06S P>

using System;
using System.Linq.Expressions;

namespace DifferentPropertSetterStrategies
{
   class TestClass
   {
      public string XY
      {
         get;
         set;
      }
   }

   class DelegateFactory
   {
      public static Action<object, object> GenerateSetPropertyActionForControl(
         )
      {
         return (inst, val) => ((TestClass) inst).XY = (string) val;
      }

      public static Action<object, object> GenerateSetPropertyActionWithReflection(
         Type type,
         string property
         )
      {
         var propertyInfo = type.GetProperty(property);

         return (inst, val) => propertyInfo.SetValue (inst, val, null);
      }

      public static Action<object,object> GenerateSetPropertyActionWithLinqExpression (
         Type type,
         string property
         )
      {
         var propertyInfo = type.GetProperty(property);
         var propertyType = propertyInfo.PropertyType;

         var instanceParameter = Expression.Parameter(typeof(object), "instance");
         var valueParameter = Expression.Parameter(typeof(object), "value");

         var lambda = Expression.Lambda<Action<object, object>> (
            Expression.Assign (
               Expression.Property (Expression.Convert (instanceParameter, type), propertyInfo),
               Expression.Convert(valueParameter, propertyType)),
            instanceParameter,
            valueParameter
            );

         return lambda.Compile();
      }
   }

   static class Program
   {
      static void Time (
         string tag, 
         object instance,
         object value,
         Action<object, object > action
         )
      {
         // Cold run
         action(instance, value);

         var then = DateTime.Now;
         const int Count = 2000000;
         for (var iter = 0; iter < Count; ++iter)
         {
            action (instance, value);
         }
         var diff = DateTime.Now - then;
         Console.WriteLine ("{0} {1} times - {2:0.00}s", tag, Count, diff.TotalSeconds);

      }

      static void Main(string[] args)
      {
         var instance = new TestClass ();
         var instanceType = instance.GetType ();

         const string TestProperty = "XY";
         const string TestValue = "Test";

         // Control case which just uses a hard coded delegate
         Time(
            "Control",
            instance,
            TestValue,
            DelegateFactory.GenerateSetPropertyActionForControl ()
            );

         Time(
            "Reflection", 
            instance, 
            TestValue, 
            DelegateFactory.GenerateSetPropertyActionWithReflection (instanceType, TestProperty)
            );

         Time(
            "Expression Trees", 
            instance, 
            TestValue, 
            DelegateFactory.GenerateSetPropertyActionWithLinqExpression(instanceType, TestProperty)
            );

         Console.ReadKey();
      }

   }
}


2 commentaires

Ce sont les 4 manières différentes (que je connais) Comment définir une propriété sans réflexion: 1. Délégué.Create 2. DynamicMethod 3. Arbres d'expression 4. Modifier <>. Créer


J'ai ajouté un extrait de code d'arbre d'expression plus rapide en bas.



2
votes

Le cadre open source Impromptutrinterface a des méthodes à appeler sur la base d'une chaîne à l'aide du DLR plutôt que de la réflexion et fonctionne plus rapidement que la réflexion.

Impromptu.InvokeSet(localeEntity, values[j].EntityPropertyName,value);


0 commentaires

3
votes

Pour la réponse de Fulesnabel, vous pouvez accélérer beaucoup (parfois deux fois plus vite dans mes tests). Dans certains tests, il était tout aussi rapide que la solution de contrôle: xxx


3 commentaires

Où passez la valeur de la propriété! Je suis nouveau sur les expressions, je ne trouve tout simplement pas la pièce pour voir la valeur comme dans l'exemple précédent, il transmet la valeur via la variable "Val"


action callsetName = generateetpropertyactionwithlinqexpression2 (typeof (personne), "premier nom"); puis personne p = nouvelle personne (); CallsetName (P, "Bob");


@Loathing Cela pourrait réellement fonctionner pour ce que je cherche à faire. J'ai besoin d'une solution complètement générique pour définir les valeurs des propriétés en fonction de la liste des chaînes. ..Merci..