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

C#4.0,检测是否缺少方法

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

    因此,我想知道是否可以使用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;
    }
    

    Member Exists Dynamic C# 4.0

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

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

    如果对象没有该属性,则GetProroperty()将返回null。您可以对字段(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:正如@arbitrator指出的那样,“这仅对本机.net动态对象有效。例如,这对IDispatch不起作用。”

        2
  •  5
  •   flq    16 年前

    我刚刚花了将近一个小时的时间寻找在动态上获得某种红宝石般的“ResponseTo”方法的方法。当然没有一个简单的答案,但我还没有放弃。

    在反思中提出的观点应该是值得尝试的。

    使用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
    

    更新:

    既然我被否决了,还有什么比扩展方法的微妙命名更简洁的呢: 炸药 (格迪特?)!吞下例外,什么都不做 坏的 这不是生产代码,而是概念验证尖峰的版本1。我总是忘记,在像stackoverflow这样的数千人论坛上,你不能很微妙。我有罪。

        3
  •  3
  •   Jaykul    15 年前

    18个月后。..看起来你真正想要的东西现在已经发布了。这是 TryGet会员 , 等等……实际上,可能 TrySetMember 具体来说。

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

        4
  •  -1
  •   clemahieu    16 年前

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

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

        5
  •  -1
  •   Andriy Volkov    16 年前

    想想看:由于目标类可以为不存在的成员提供自己的成员查找和调用实现(通过实现IDynamicObject或子类化DynamicObject),因此这是验证成员是否存在的唯一方法 就是调用它,看看对象是处理它还是抛出异常 .

    再一次,处理不存在的成员是动态的!

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

    如果答案指出了真相,那么否决它是不公平的——即。 可靠的 在动态调度环境中检查成员存在的方法 除了调用成员 .

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