7
votes

C # 4.0, détecter si une méthode est manquante

J'ai une situation où je veux ajouter des prises de ligne aux objets CodeDom. Mais certains objets du CODE DOM ont la propriété LinePRAGMA et certains ne le font pas.

Je me demande donc s'il est possible d'utiliser le mot-clé dynamique pour détecter si la propriété existe sur l'objet (sans jeter une exception) et s'il ajoute ensuite le pragma. Voici ma méthode actuelle: xxx

mise à jour: La solution que j'ai accompagnée était d'ajouter une méthode d'extension appelée existe (). J'ai écrit un article de blog à ce sujet ici: Membre existe dynamique C # 4.0

La jist a pour but de créer une méthode d'extension qui renvoie un objet qui implémente le trygetmember de DynamicObject. Il utilise la réflexion pour revenir en vrais ou faux. Qui vous permet d'écrire du code comme celui-ci: xxx


0 commentaires

6 Réponses :


8
votes

Vous pouvez détecter si un objet possède une propriété sans avoir à utiliser les fonctionnalités dynamiques de C # 4.0 - à l'aide des fonctionnalités de réflexion qui sont autour depuis un moment (je connais au moins .NET 2.0, pas sûr de <2.0) XXX

Si l'objet n'a pas la propriété, alors getProperty () retournera null. Vous pouvez faire la même chose pour les champs (Getfield ()) et les méthodes (getMethod ()).

Non seulement cela, mais une fois que vous avez la propriétéInfo, vous pouvez l'utiliser directement pour effectuer votre ensemble: xxx

Si vous n'êtes pas sûr de savoir si la propriété a une méthode définie, vous pouvez prendre la route encore plus sûre: xxx

ceci vous donne également l'avantage supplémentaire d'être un peu plus performant sur la surcharge de recherche de l'appel dynamique (ne peut pas trouver une référence pour cette déclaration, donc je vais simplement le flotter).

i Supposons que cela ne réponde pas directement à votre question, mais plutôt une solution alternative pour accomplir le même objectif. Je n'ai pas encore utilisé les caractéristiques # 4.0 encore (même si je suis un grand fan de la dactylographie dynamique disponible dans Ruby). Il n'est certainement pas aussi propre / lisible que la solution dynamique, mais si vous ne voulez pas lancer une exception, ce sera peut-être le moyen d'aller.

EDIT: comme @Arbiter souligne: "Ceci est valide Seulement pour les objets dynamiques de Native .NET. Cela ne fonctionnera pas par exemple pour IDISPATCH. "


7 commentaires

Ceci est valable uniquement pour les objets dynamiques de Native .NET. Cela ne fonctionnera pas par exemple pour IDISPATCH.


@Arbiter Ahh, bon point. Démontrant clairement mon manque d'expérience en réalité en utilisant .NET 4.0. +1


@zvolkov Je ne comprends pas pourquoi votre réponse suggère que celle-ci ne fonctionnera pas - pouvez-vous élaborer?


C'était ce que j'ai fini par faire aussi. J'espérais juste qu'il y aurait un moyen plus intelligent et élégant de le faire avec le mot clé dynamique. Ou du moins que l'appelant une propriété inexistante ne lancerait pas une exception :(


La question ne se pose pas que cela fonctionne pour un objet dynamique, mais surtout pour les classes de l'espace de nom de CodeDom. L'API est quelque peu désordonnée: il n'y a pas d'indicateurs que les classes ont une pragme de ligne et qui ne le font pas. Donc, vous êtes coincé avec beaucoup de chèques de type ou faites quelque chose avec une réflexion ou utilisez effectivement dynamique.


Cela ne fonctionnera pas si la classe cible implémente IdynamicObject ou sous-classes DynamicObject. Voir ma réponse ci-dessous pour plus de détails.


Je suis allé avec une approche réflexion à la fin. Voici ma solution: Justnbusiness.com / Post / 2009/07/02 / ... a essentiellement une API de style fluide avec une enveloppe dynamique pour voir si des membres inconnus existent en premier.



5
votes

Je viens de passer presque une heure à chercher des moyens d'obtenir une sorte de méthode de "réponse" rubis-esque sur dynamique. Il n'y a certainement pas une réponse facile, mais je n'ai pas encore abandonné.

Le point de réflexion devrait être la chose à essayer.

avec dynamique, la seule chose que je reçois jusqu'à présent est une méthode d'extension qui traite votre objet comme dynamique. Si cela fonctionne, cela fonctionne, sinon il échoue silencieusement ... xxx

alors vous pouvez faire ... xxx < p> mise à jour:

Depuis que je reçois des bowvotes et que je me suis laissé être plus concis que la nommage subtile de la méthode d'extension: il est dynamite < / fort> (Geddit?)! Gobblier des exceptions et ne rien faire est mauvais . Ce n'est pas un code de production, mais une version 1 d'une pointe d'une preuve de concept. Je continue d'oublier que vous ne pouvez pas être subtil sur un forum de plusieurs milliers comme Stackoverflow. MEA CULPA.


4 commentaires

+1 assez cool trucs. Mais quand commence-t-il à devenir trop intelligent?


Je ne suis pas sûr de la défaillance silencieuse, on sonne comme la configuration d'un scénario où un bogue disparaîtra dans un trou noir d'obscurité. Dans Ruby, vous obtenez toujours une erreur de temps d'exécution s'il n'y a pas de méthode - sauf si la classe définit également la méthode_missing méthode. Et même alors, vous avez le choix de le gérer comme vous le voyez et déposez toujours une erreur «méthode non définie» si vous le souhaitez.


La méthode de l'extension n'invie-t-elle que d'une exception RuntimeBinderException, qui est le comportement souhaité dans ce scénario. Toutes les autres exceptions passeraient la pile d'appels. Je ne vois pas le problème ici.


J'ai pensé que Theght the "pourrait" mal orthographié était un peu une blague depuis la méthode "pourrait" exister?



-1
votes

Je vais faire trimer et dire que la typographie statique éviterait ce problème.

Ceci est un candidat à une méthode abstraite avec une priorité.


1 commentaires

Eh bien, le problème ici est que j'essaie d'accéder à une propriété sur des objets CodeDom. Si vous ne connaissez pas, il y en a probablement 50 d'entre eux et peut-être que la moitié de la propriété de la ligne. Malheureusement, cette propriété n'a pas été trouvée sur un type de base ou une interface de base partagée particulière. Donc, avec une prise de dactylographie forte, vous devez essayer d'échouer de tout un tas d'objets afin de trouver le bon. Très fastidieux.



-1
votes

Pensez-y: puisque la classe cible peut fournir sa propre implémentation pour la recherche de membre et l'invocation des membres non existants (en mettant en œuvre IdynamicObject ou sous-classement dynamicObject), le seul moyen de vérifier si un membre existe est d'invoquer et voir si l'objet le gère ou jette une exception .

Encore une fois, la manipulation des membres non existants est dynamique!

- Edit -

Si vous contrôlez la création d'objets, vous pouvez sous-classer la classe et implémenter idynnamicObject pour signaler votre autre classe cette méthode n'existe pas.

Il est injuste de descendre la réponse si cela indique la vérité - c'est-à-dire qu'il n'y a pas et ne peut pas être A moyen de vérifier l'existence des membres dans l'environnement Dynamic Dispatch Dispatch Environment < fort> autre que d'invoquer le membre .


4 commentaires

Ce n'est pas mon type, je ne peux pas ajouter des interfaces aussi. :(


En outre, invoquer un membre inexistant jette une exception. J'ai besoin de plus d'un type de chose Tryinvoke.


C'est tout ce qui est agréable, mais la question concerne les objets codedom, qui ne sont pas dynamiques. Et il se demandait simplement si c # 4 pourrait aider à découvrir la propriété. De plus, il n'y a pas besoin de casage supérieur une phrase entière juste pour essayer de faire un point.


Le titre était "C # 4.0, détecte si une méthode est manquante" - ce que j'ai adressé exactement. Point valide RE: Capses, résolus.



3
votes

18 mois plus tard ... Cela semble être ce que tu voulais vraiment, c'est là maintenant que c'est libéré. C'est le trygetmember , trygetvalue , etc ... en fait, probablement TRYSETMember , plus précisément.

http://msdn.microsoft.com/fr -us / bibliothèque / system.dynamic.dynamicocobject_members.aspx


1 commentaires

Trygetmember n'existe que sur des objets qui héritent de dynamicobject si ... la jeter à (dynamique) n'est pas tout à fait la même chose que de la jeter à (dynamicobject). Lorsque vous le jetez dynamique et essayez d'appeler les membres dessus, il appellera trygetvalue sur le wrapper dynamique et lancer une exception si elle échoue. Je suppose qu'il pourrait peut-être le jeter comme "(dynamicObject) (dynamique) obj"?



-1
votes
    using System.Collections.Generic;
using System.Linq.Expressions;

namespace System.Dynamic
{
    //
    // Summary:
    //     Provides a base class for specifying dynamic behavior at run time. This class
    //     must be inherited from; you cannot instantiate it directly.
    public class DynamicObject : IDynamicMetaObjectProvider
    {
        //
        // Summary:
        //     Enables derived types to initialize a new instance of the System.Dynamic.DynamicObject
        //     type.
        protected DynamicObject();

        //
        // Summary:
        //     Returns the enumeration of all dynamic member names.
        //
        // Returns:
        //     A sequence that contains dynamic member names.
        public virtual IEnumerable<string> GetDynamicMemberNames();
        //
        // Summary:
        //     Provides a System.Dynamic.DynamicMetaObject that dispatches to the dynamic virtual
        //     methods. The object can be encapsulated inside another System.Dynamic.DynamicMetaObject
        //     to provide custom behavior for individual actions. This method supports the Dynamic
        //     Language Runtime infrastructure for language implementers and it is not intended
        //     to be used directly from your code.
        //
        // Parameters:
        //   parameter:
        //     The expression that represents System.Dynamic.DynamicMetaObject to dispatch to
        //     the dynamic virtual methods.
        //
        // Returns:
        //     An object of the System.Dynamic.DynamicMetaObject type.
        public virtual DynamicMetaObject GetMetaObject(Expression parameter);
        //
        // Summary:
        //     Provides implementation for binary operations. Classes derived from the System.Dynamic.DynamicObject
        //     class can override this method to specify dynamic behavior for operations such
        //     as addition and multiplication.
        //
        // Parameters:
        //   binder:
        //     Provides information about the binary operation. The binder.Operation property
        //     returns an System.Linq.Expressions.ExpressionType object. For example, for the
        //     sum = first + second statement, where first and second are derived from the DynamicObject
        //     class, binder.Operation returns ExpressionType.Add.
        //
        //   arg:
        //     The right operand for the binary operation. For example, for the sum = first
        //     + second statement, where first and second are derived from the DynamicObject
        //     class, arg is equal to second.
        //
        //   result:
        //     The result of the binary operation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryBinaryOperation(BinaryOperationBinder binder, object arg, out object result);
        //
        // Summary:
        //     Provides implementation for type conversion operations. Classes derived from
        //     the System.Dynamic.DynamicObject class can override this method to specify dynamic
        //     behavior for operations that convert an object from one type to another.
        //
        // Parameters:
        //   binder:
        //     Provides information about the conversion operation. The binder.Type property
        //     provides the type to which the object must be converted. For example, for the
        //     statement (String)sampleObject in C# (CType(sampleObject, Type) in Visual Basic),
        //     where sampleObject is an instance of the class derived from the System.Dynamic.DynamicObject
        //     class, binder.Type returns the System.String type. The binder.Explicit property
        //     provides information about the kind of conversion that occurs. It returns true
        //     for explicit conversion and false for implicit conversion.
        //
        //   result:
        //     The result of the type conversion operation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryConvert(ConvertBinder binder, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that initialize a new instance of
        //     a dynamic object. This method is not intended for use in C# or Visual Basic.
        //
        // Parameters:
        //   binder:
        //     Provides information about the initialization operation.
        //
        //   args:
        //     The arguments that are passed to the object during initialization. For example,
        //     for the new SampleType(100) operation, where SampleType is the type derived from
        //     the System.Dynamic.DynamicObject class, args[0] is equal to 100.
        //
        //   result:
        //     The result of the initialization.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryCreateInstance(CreateInstanceBinder binder, object[] args, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that delete an object by index. This
        //     method is not intended for use in C# or Visual Basic.
        //
        // Parameters:
        //   binder:
        //     Provides information about the deletion.
        //
        //   indexes:
        //     The indexes to be deleted.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes);
        //
        // Summary:
        //     Provides the implementation for operations that delete an object member. This
        //     method is not intended for use in C# or Visual Basic.
        //
        // Parameters:
        //   binder:
        //     Provides information about the deletion.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryDeleteMember(DeleteMemberBinder binder);
        //
        // Summary:
        //     Provides the implementation for operations that get a value by index. Classes
        //     derived from the System.Dynamic.DynamicObject class can override this method
        //     to specify dynamic behavior for indexing operations.
        //
        // Parameters:
        //   binder:
        //     Provides information about the operation.
        //
        //   indexes:
        //     The indexes that are used in the operation. For example, for the sampleObject[3]
        //     operation in C# (sampleObject(3) in Visual Basic), where sampleObject is derived
        //     from the DynamicObject class, indexes[0] is equal to 3.
        //
        //   result:
        //     The result of the index operation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a run-time exception is thrown.)
        public virtual bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that get member values. Classes derived
        //     from the System.Dynamic.DynamicObject class can override this method to specify
        //     dynamic behavior for operations such as getting a value for a property.
        //
        // Parameters:
        //   binder:
        //     Provides information about the object that called the dynamic operation. The
        //     binder.Name property provides the name of the member on which the dynamic operation
        //     is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty)
        //     statement, where sampleObject is an instance of the class derived from the System.Dynamic.DynamicObject
        //     class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies
        //     whether the member name is case-sensitive.
        //
        //   result:
        //     The result of the get operation. For example, if the method is called for a property,
        //     you can assign the property value to result.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a run-time exception is thrown.)
        public virtual bool TryGetMember(GetMemberBinder binder, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that invoke an object. Classes derived
        //     from the System.Dynamic.DynamicObject class can override this method to specify
        //     dynamic behavior for operations such as invoking an object or a delegate.
        //
        // Parameters:
        //   binder:
        //     Provides information about the invoke operation.
        //
        //   args:
        //     The arguments that are passed to the object during the invoke operation. For
        //     example, for the sampleObject(100) operation, where sampleObject is derived from
        //     the System.Dynamic.DynamicObject class, args[0] is equal to 100.
        //
        //   result:
        //     The result of the object invocation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.
        public virtual bool TryInvoke(InvokeBinder binder, object[] args, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that invoke a member. Classes derived
        //     from the System.Dynamic.DynamicObject class can override this method to specify
        //     dynamic behavior for operations such as calling a method.
        //
        // Parameters:
        //   binder:
        //     Provides information about the dynamic operation. The binder.Name property provides
        //     the name of the member on which the dynamic operation is performed. For example,
        //     for the statement sampleObject.SampleMethod(100), where sampleObject is an instance
        //     of the class derived from the System.Dynamic.DynamicObject class, binder.Name
        //     returns "SampleMethod". The binder.IgnoreCase property specifies whether the
        //     member name is case-sensitive.
        //
        //   args:
        //     The arguments that are passed to the object member during the invoke operation.
        //     For example, for the statement sampleObject.SampleMethod(100), where sampleObject
        //     is derived from the System.Dynamic.DynamicObject class, args[0] is equal to 100.
        //
        //   result:
        //     The result of the member invocation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result);
        //
        // Summary:
        //     Provides the implementation for operations that set a value by index. Classes
        //     derived from the System.Dynamic.DynamicObject class can override this method
        //     to specify dynamic behavior for operations that access objects by a specified
        //     index.
        //
        // Parameters:
        //   binder:
        //     Provides information about the operation.
        //
        //   indexes:
        //     The indexes that are used in the operation. For example, for the sampleObject[3]
        //     = 10 operation in C# (sampleObject(3) = 10 in Visual Basic), where sampleObject
        //     is derived from the System.Dynamic.DynamicObject class, indexes[0] is equal to
        //     3.
        //
        //   value:
        //     The value to set to the object that has the specified index. For example, for
        //     the sampleObject[3] = 10 operation in C# (sampleObject(3) = 10 in Visual Basic),
        //     where sampleObject is derived from the System.Dynamic.DynamicObject class, value
        //     is equal to 10.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.
        public virtual bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value);
        //
        // Summary:
        //     Provides the implementation for operations that set member values. Classes derived
        //     from the System.Dynamic.DynamicObject class can override this method to specify
        //     dynamic behavior for operations such as setting a value for a property.
        //
        // Parameters:
        //   binder:
        //     Provides information about the object that called the dynamic operation. The
        //     binder.Name property provides the name of the member to which the value is being
        //     assigned. For example, for the statement sampleObject.SampleProperty = "Test",
        //     where sampleObject is an instance of the class derived from the System.Dynamic.DynamicObject
        //     class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies
        //     whether the member name is case-sensitive.
        //
        //   value:
        //     The value to set to the member. For example, for sampleObject.SampleProperty
        //     = "Test", where sampleObject is an instance of the class derived from the System.Dynamic.DynamicObject
        //     class, the value is "Test".
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TrySetMember(SetMemberBinder binder, object value);
        //
        // Summary:
        //     Provides implementation for unary operations. Classes derived from the System.Dynamic.DynamicObject
        //     class can override this method to specify dynamic behavior for operations such
        //     as negation, increment, or decrement.
        //
        // Parameters:
        //   binder:
        //     Provides information about the unary operation. The binder.Operation property
        //     returns an System.Linq.Expressions.ExpressionType object. For example, for the
        //     negativeNumber = -number statement, where number is derived from the DynamicObject
        //     class, binder.Operation returns "Negate".
        //
        //   result:
        //     The result of the unary operation.
        //
        // Returns:
        //     true if the operation is successful; otherwise, false. If this method returns
        //     false, the run-time binder of the language determines the behavior. (In most
        //     cases, a language-specific run-time exception is thrown.)
        public virtual bool TryUnaryOperation(UnaryOperationBinder binder, out object result);
    }`enter code here`
}

0 commentaires