代码之家  ›  专栏  ›  技术社区  ›  justin.m.chase

C 4.0,检测是否缺少方法

  •  7
  • justin.m.chase  · 技术社区  · 15 年前

    在这种情况下,我想向codedom对象添加linepragma。但有些代码dom对象具有linepragma属性,而有些则没有。

    因此,我想知道是否可以使用dynamic关键字来检测对象上是否存在该属性(不引发异常),如果存在,则添加pragma。这是我目前的方法:

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

    更新: 我使用的解决方案是添加名为exists()的扩展方法。我在这里写了一篇关于它的博客: Member Exists Dynamic C# 4.0

    jist将创建一个扩展方法,该方法返回一个实现DynamicObject的TryGetMember的对象。它使用反射,然后返回真或假。它允许您编写这样的代码:

    object instance = new { Foo = "Hello World!" };
    if (instance.Reflection().Exists().Foo)
    {
        string value = instance.Reflection().Call().Foo;
        Console.WriteLine(value);
    }
    
    6 回复  |  直到 7 年前
        1
  •  8
  •   Brent Arias    9 年前

    您可以检测对象是否具有属性,而不必使用C 4.0的动态功能-而使用已经存在一段时间的反射功能(我至少知道.NET 2.0,不确定<2.0)

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

    如果对象没有该属性,则getProperty()将返回空值。您可以对字段(getField())和方法(getMethod())执行类似的操作。

    不仅如此,而且一旦拥有了propertyinfo,就可以直接使用它来进行设置:

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

    如果不确定属性是否具有set方法,则可以采用更安全的路径:

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

    这还为您提供了一个额外的好处,即比动态调用的查找开销更具性能(找不到该语句的引用,所以我只将其浮动在那里)。

    我想这不是直接回答你的问题,而是实现同一目标的另一种解决方案。实际上,我还没有使用4.0特性(尽管我非常喜欢Ruby中的动态类型)。当然,它没有动态解决方案那么干净/可读,但是如果您不想抛出异常,那么它可能是一种可行的方法。

    edit:as@arbiter指出,“这只对本机.NET动态对象有效。例如,对于IDispatch,这将不起作用。”

        2
  •  5
  •   flq    15 年前

    我刚刚花了将近一个小时的时间寻找在动态上获得某种类似于红宝石的“respondto”方法的方法。答案当然不容易,但我还没有放弃。

    反省的观点应该是值得尝试的。

    对于dynamic,目前为止我只得到一个将对象视为动态的扩展方法。如果它起作用,它就起作用,如果不起作用,它就会默默地失败…

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

    那你就可以…

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

    更新:

    既然我被否决了,你让我比扩展方法的微妙命名更简洁些:它是 炸药 (GEDDIT?)!狼吞虎咽的异常和无所作为是 坏的 .这不是生产代码,而是概念验证峰值的版本1。我一直忘了,在StackOverflow这样的数千个论坛上,你不能表现得很微妙。我是罪魁祸首。

        3
  •  3
  •   Jaykul    14 年前

    18个月后…看来你真正想要的是现在它已经发布了。这是 特里格特成员 , TyGET值 等。实际上,可能 TrySetMember 具体来说。

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

        4
  •  -1
  •   clemahieu    15 年前

    我要插话说静态输入可以避免这个问题。

    这是具有重写功能的抽象方法的候选项。

        5
  •  -1
  •   Andriy Volkov    15 年前

    考虑一下:由于目标类可以为非现有成员的成员查找和调用提供自己的实现(通过实现idynamicObject或对dynamicObject进行子类化),因此验证成员是否存在的唯一方法就是 是调用它并查看对象是处理它还是抛出异常 .

    再次强调,非现有成员的处理是动态的!

    --编辑——

    如果控制对象创建,则可以对类进行子类化并实现IDynamicObject,以向其他类发出方法不存在的信号。

    如果答案指出了真相,那么轻率地否定答案是不公平的——也就是说。 没有也不能 可靠的 动态调度环境下构件存在性的检验方法 除了调用成员 .

        6
  •  -1
  •   Pit Zh    7 年前
        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`
    }