Pregunta

Tengo una situación en la que quiero agregar LinePragmas a objetos CodeDom.Pero algunos objetos de código dom tienen la propiedad LinePragma y otros no.

Entonces me pregunto si es posible usar la palabra clave dinámica para detectar si la propiedad existe en el objeto (sin generar una excepción) y, si es así, agregar el pragma.Aquí está mi método actual:

public static T SetSource<T>(this T codeObject, INode sourceNode)
    where T : CodeObject
{
    codeObject.UserData["Node"] = sourceNode.Source;
    dynamic dynamicCodeObject = codeObject;

    // How can I not throw an exception here?
    if (dynamicCodeObject.LinePragma != null)
    {
        dynamicCodeObject.LinePragma = new CodeLinePragma(
        sourceNode.Source.Path.AbsoluteUri,
        sourceNode.Source.StartLine);
    }

    return codeObject;
}

ACTUALIZAR:La solución que elegí fue agregar un método de extensión llamado Exists().Escribí una publicación de blog al respecto aquí:El miembro existe dinámico C# 4.0

La idea era crear un método de extensión que devuelva un objeto que implemente TryGetMember de DynamicObject.Utiliza la reflexión para luego devolver verdadero o falso.Lo que te permite escribir código como este:

object instance = new { Foo = "Hello World!" };
if (instance.Reflection().Exists().Foo)
{
    string value = instance.Reflection().Call().Foo;
    Console.WriteLine(value);
}
¿Fue útil?

Solución

Puede detectar si un objeto tiene una propiedad sin tener que usar las características dinámicas de C # 4.0 - en lugar de utilizar las características de reflexión que han estado alrededor por un tiempo (Conozco al menos .NET 2.0, no está seguro acerca de <2,0)

PropertyInfo info = codeObject.getType().GetProperty(
    "LinePragma", 
    BindingFlags.Public | BindingFlags.Instance
)

Si el objeto no tiene la propiedad, entonces GetProperty () devolverá nulo. Usted puede hacer similar para los campos (GetField ()) y métodos (GetMethod ()).

No sólo eso, sino que una vez que tenga la PropertyInfo, se puede usar directamente para hacer su conjunto:

info.SetValue(codeObject, new CodeLinePragma(), null);

Si no está seguro de si la propiedad tiene un método set, se puede tomar la ruta más segura:

MethodInfo method = info.GetSetMethod();
if(method != null)
    method.Invoke(codeObject, new object[]{ new CodeLinePragma() });

Esto también le da la ventaja añadida de ser un poco más performante sobre la sobrecarga de búsqueda de la llamada dinámica (no puede encontrar una referencia de esa declaración, así que voy a flotar por ahí).

supongo que eso no responde a su pregunta directamente, sino más bien es una solución alternativa para lograr el mismo objetivo. No he utilizado realmente # 4.0 características todavía (a pesar de que yo soy un gran fan de la tipificación dinámica disponible en Ruby). Ciertamente, no tan limpio / legible como la solución dinámica, pero si usted no desea lanzar una excepción puede ser el camino a seguir.

Edit: Como @arbiter señala, ". Esto es válido sólo para los objetos dinámicos .net nativos Esto no funcionará por ejemplo para IDispatch"

Otros consejos

Pasé casi una hora buscando formas de obtener algún tipo de método "RespondTo" estilo Ruby en dinámico.Ciertamente no hay una respuesta fácil, pero todavía no me he rendido.

Lo que se debe intentar es lo que se plantea en la reflexión.

Con dinámico, lo único que obtengo hasta ahora es un método de extensión que trata su objeto como dinámico.Si funciona, funciona, si no, falla silenciosamente...

public static void Dynamight<T>(this T target, Action<dynamic> action)
{
  dynamic d = target;
  try
  {
    action(d);
  }
  catch (RuntimeBinderException)
  {
    //That was that, didn't work out
  }
}

Entonces puedes hacer...

string h = "Hello";
h.Dynamight(d => Console.WriteLine(d.Length)); //Prints out 5
h.Dynamight(d => d.Foo()); //Nothing happens

Actualizar:

Dado que estoy recibiendo votos negativos y lo que sea, déjame ser más conciso que el nombre sutil del método de extensión:Es dinamita (¿Geddit?)!Engullir excepciones y no hacer nada es malo.Este no es un código de producción, sino una versión 1 de una prueba de concepto.Sigo olvidando que no se puede ser sutil en un foro de miles de personas como stackoverflow.Mea culpa.

18 meses después ... parece que lo que realmente quería es que hay ahora que se ha puesto en libertad. Es la TryGetMember , TryGetValue , etc ... en realidad, probablemente TrySetMember , específicamente.

http://msdn.microsoft.com/en -us / biblioteca / system.dynamic.dynamicobject_members.aspx

Me voy a meter su cuchara y decir tipos estáticos evitaría este problema.

Este es un candidato para un método abstracto con primordial.

Piense en esto: ya que la clase de objetivo puede proporcionar su propia implementación de la consulta de miembro y la invocación de los miembros no-existente (mediante la implementación de IDynamicObject o DynamicObject subclases) la única manera de verificar si existe un miembro de es invocar y ver si el objeto lo maneja o se produce una excepción .

Una vez más, la manipulación de los miembros no existentes es dinámico!

- Editar -

Si el control de la creación de objetos, que podría subclase de la clase y poner en práctica IDynamicObject para señalar su otra clase que el método no existe.

Es injusto downvote la respuesta si se señala la verdad - es decir, que no hay y no puede ser una manera confiable para comprobar la existencia miembro en el entorno de envío dinámico < strong> otro de invocar el miembro .

    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`
}
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top