C # 4.0, determine if a method is missing

I have a situation where I want to add LinePragmas objects to CodeDom objects. But some dom code objects have the LinePragma property, and some do not.

So, I am wondering if you can use a dynamic keyword to determine if a property exists on an object (without exception), and if it does, add a pragma. Here is my current method:

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

UPDATE: The solution I went with was to add an Exists () extension method. I wrote a blog post about it here: Member Exists Dynamic C # 4.0

The bottom line was to create an extension method that returns an object that implements DynamicObject TryGetMember. It uses reflection and then returns true or false. Which allows you to write this code:

 object instance = new { Foo = "Hello World!" }; if (instance.Reflection().Exists().Foo) { string value = instance.Reflection().Call().Foo; Console.WriteLine(value); } 
+7
c # dynamic codedom
source share
6 answers

You can determine if an object has a property without using the dynamic functions of C # 4.0 - instead, it uses reflection functions that have been around for some time (I know at least .NET 2.0, not sure about <2.0)

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

If the object does not have a property, then GetProperty () will return null. You can do similar for fields (GetField ()) and methods (GetMethod ()).

Not only this, but as soon as you have PropertyInfo, you can use it directly to execute your set:

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

If you are not sure if the property has a given method, you can take an even more secure route:

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

It also gives you the added benefit of being a little more efficient than the overhead of a dynamic call (can't find a link for this statement, so I'll just swim there).

I believe that this does not directly answer your question, but rather is an alternative solution to achieve the same goal. I haven't used feature # 4.0 yet (although I'm a huge fan of dynamic printing, available in Ruby). This, of course, is not as clean and readable as a dynamic solution, but if you do not want to throw an exception, this may be the way to go.

EDIT: as @arbiter points out, "This is only true for inline dynamic .net objects. This does not work, for example, for IDispatch."

+8
source share

I just spent almost an hour looking for ways to get some kind of ruby ​​RespondTo method in dynamics. Of course, the answer is not easy, but I have not given up yet.

The point made by reflection should be what you need to try.

With dynamics, the only thing I get so far is the extension method, which treats your object as dynamic. If it works, it works, if it does not fail silently ...

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

Then you can do ...

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

Update:

Since I get downvotes and what-you-let me be shorter than subtle naming of the extension method: is it dynamite (Geddit?)! Throwing exceptions and doing nothing wrong. This is not production code, but version 1 of a burst of proof of concept. I keep forgetting that you cannot be subtle in a multi-volume forum like stackoverflow. Mea culpa.

+4
source share

18 months later ... it looks like you really wanted it now released. These are TryGetMember , TryGetValue , etc. Actually, perhaps TrySetMember in particular.

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

+3
source share

I am going to call back and say that static typing will avoid this problem.

This is a candidate for an abstract method with redefinition.

-one
source share

Think about it: since the target class can provide its own implementation for finding and calling an element for non-existent members (by implementing IDynamicObject or a subclass of DynamicObject), the only way to check if an element exists is to call it and see if the object processes it or throws an exception .

Re-processing non-existent DYNAMIC elements!

- EDIT -

If you control the creation of an object, you can subclass the class and implement IDynamicObject to tell another class that this method does not exist.

It is unfair to reduce the answer if it indicates the truth, i.e. , which is not and cannot be a reliable way to verify the existence of members in a dynamic sending environment , other than calling the element .

-one
source share
  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` } 
-one
source share

All Articles