88 votes

Comment créer des propriétés dynamiques en c# ?

Je suis à la recherche d’un moyen de créer une classe avec un jeu de propriétés statiques. Au moment de l’exécution, je veux pouvoir ajouter d’autres propriétés dynamiques pour cet objet de la base de données. Je tiens aussi à ajouter le tri et le filtrage des fonctionnalités à ces objets.

Comment je fais cela en c# ?

62voto

Paolo Tedesco Points 22442

Vous pouvez utiliser un dictionnaire, dire

Je pense que dans la plupart des cas où quelque chose de semblable se fait, c’est fait comme ça.
Dans tous les cas, vous n'aurait pas gagner quelque chose crée une propriété « réelle » avec jeu et obtenir les accesseurs, puisqu’il serait créé seulement en cours d’exécution et vous ne serait pas l’utiliser dans votre code...

Voici un exemple, montrant une implémentation possible de filtrage et de tri (aucune vérification des erreurs) :

30voto

Marc Gravell Points 482669

Si vous en avez besoin pour la liaison de données, vous pouvez le faire avec un descripteur personnalisé modèle... par la mise en œuvre de ICustomTypeDescriptor, TypeDescriptionProvider et/ou TypeCoverter, vous pouvez créer votre propre PropertyDescriptor cas au moment de l'exécution. C'est ce que les commandes comme DataGridView, PropertyGrid etc utiliser pour afficher les propriétés.

De se lier à des listes, vous auriez besoin d' ITypedList et IList; pour la base de tri: IBindingList; pour le filtrage et avancées de tri: IBindingListView; pour une "nouvelle ligne" de soutien (DataGridView): ICancelAddNew (ouf!).

Il est un beaucoup de travail même si. DataTable (bien que je déteste) est moyen pas cher de faire la même chose. Si vous n'avez pas besoin de liaison de données, il suffit d'utiliser une table de hachage ;-p

Voici un exemple simple - mais vous pouvez faire beaucoup plus...

30voto

samir105 Points 505

Utilisez ExpandoObject comme le ViewBag dans MVC 3.

12voto

Aric TenEyck Points 5434

Créer une table de hachage appelé « Propriétés » et ajouter vos propriétés.

12voto

Alun Harford Points 2373

Je ne suis pas sûr que vous voulez vraiment faire ce que vous dites que vous voulez faire, mais ce n'est pas pour moi que de raison!

Vous ne pouvez pas ajouter des propriétés à une classe après qu'il a été JITed.

Le plus proche que vous pourriez obtenir serait de créer dynamiquement un sous-type avec la Réflexion.Émettre et de copier les champs existants, mais vous auriez à jour toutes les références à l'objet vous-même.

Vous aussi ne pas être en mesure d'accéder à ces propriétés au moment de la compilation.

Quelque chose comme:

public class Dynamic
{
    public Dynamic Add<T>(string key, T value)
    {
        AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicAssembly"), AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("Dynamic.dll");
        TypeBuilder typeBuilder = moduleBuilder.DefineType(Guid.NewGuid().ToString());
        typeBuilder.SetParent(this.GetType());
        PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(key, PropertyAttributes.None, typeof(T), Type.EmptyTypes);

        MethodBuilder getMethodBuilder = typeBuilder.DefineMethod("get_" + key, MethodAttributes.Public, CallingConventions.HasThis, typeof(T), Type.EmptyTypes);
        ILGenerator getter = getMethodBuilder.GetILGenerator();
        getter.Emit(OpCodes.Ldarg_0);
        getter.Emit(OpCodes.Ldstr, key);
        getter.Emit(OpCodes.Callvirt, typeof(Dynamic).GetMethod("Get", BindingFlags.Instance | BindingFlags.NonPublic).MakeGenericMethod(typeof(T)));
        getter.Emit(OpCodes.Ret);
        propertyBuilder.SetGetMethod(getMethodBuilder);

        Type type = typeBuilder.CreateType();

        Dynamic child = (Dynamic)Activator.CreateInstance(type);
        child.dictionary = this.dictionary;
        dictionary.Add(key, value);
        return child;
    }

    protected T Get<T>(string key)
    {
        return (T)dictionary[key];
    }

    private Dictionary<string, object> dictionary = new Dictionary<string,object>();
}

Je n'ai pas de VS installé sur cette machine, alors laissez-moi savoir si il y a de gros bugs (et bien d'autres... que le massif des problèmes de performances, mais je n'ai pas écrit le cahier des charges!)

Maintenant, vous pouvez utiliser:

Dynamic d = new Dynamic();
d = d.Add("MyProperty", 42);
Console.WriteLine(d.GetType().GetProperty("MyProperty").GetValue(d, null));

Vous pouvez également l'utiliser comme une propriété classique dans une langue qui prend en charge la liaison tardive (par exemple, VB.NET)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X