I'm wanting to have a simple duck typing example in C# using dynamic objects. It would seem to me, that a dynamic object should have HasValue/HasProperty/HasMethod methods with a single string parameter for the name of the value, property, or method you are looking for before trying to run against it. I'm trying to avoid try/catch blocks, and deeper reflection if possible. It just seems to be a common practice for duck typing in dynamic languages (JS, Ruby, Python etc.) that is to test for a property/method before trying to use it, then falling back to a default, or throwing a controlled exception. The example below is basically what I want to accomplish.
If the methods described above don't exist, does anyone have premade extension methods for dynamic that will do this?
Example: In JavaScript I can test for a method on an object fairly easily.
//JavaScript
function quack(duck) {
if (duck && typeof duck.quack === "function") {
return duck.quack();
}
return null; //nothing to return, not a duck
}
How would I do the same in C#?
//C# 4
dynamic Quack(dynamic duck)
{
//how do I test that the duck is not null,
//and has a quack method?
//if it doesn't quack, return null
}
Up to you whether you define "duck typing" so that this difference means C++ doesn't have it.
What languages support duck typing? Python and Ruby support duck typing, both of which are dynamic typed languages. In general, dynamic typed languages such as JavaScript and TypeScript support duck typing.
Duck typing allows an object to be passed in to a method that expects a certain type even if it doesn't inherit from that type. All it has to do is support the methods and properties of the expected type in use by the method.
Duck typing in computer programming is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine whether an object can be used for a particular purpose.
If you have control over all of the object types that you will be using dynamically, another option would be to force them to inherit from a subclass of the DynamicObject
class that is tailored to not fail when a method that does not exist is invoked:
A quick and dirty version would look like this:
public class DynamicAnimal : DynamicObject { public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result) { bool success = base.TryInvokeMember(binder, args, out result); // If the method didn't exist, ensure the result is null if (!success) result = null; // Always return true to avoid Exceptions being raised return true; } }
You could then do the following:
public class Duck : DynamicAnimal { public string Quack() { return "QUACK!"; } } public class Cow : DynamicAnimal { public string Moo() { return "Mooooo!"; } } class Program { static void Main(string[] args) { var duck = new Duck(); var cow = new Cow(); Console.WriteLine("Can a duck quack?"); Console.WriteLine(DoQuack(duck)); Console.WriteLine("Can a cow quack?"); Console.WriteLine(DoQuack(cow)); Console.ReadKey(); } public static string DoQuack(dynamic animal) { string result = animal.Quack(); return result ?? "... silence ..."; } }
And your output would be:
Can a duck quack? QUACK! Can a cow quack? ... silence ...
Edit: I should note that this is the tip of the iceberg if you are able to use this approach and build on DynamicObject
. You could write methods like bool HasMember(string memberName)
if you so desired.
Try this:
using System.Linq;
using System.Reflection;
//...
public dynamic Quack(dynamic duck, int i)
{
Object obj = duck as Object;
if (duck != null)
{
//check if object has method Quack()
MethodInfo method = obj.GetType().GetMethods().
FirstOrDefault(x => x.Name == "Quack");
//if yes
if (method != null)
{
//invoke and return value
return method.Invoke((object)duck, null);
}
}
return null;
}
Or this (uses only dynamic):
public static dynamic Quack(dynamic duck)
{
try
{
//invoke and return value
return duck.Quack();
}
//thrown if method call failed
catch (RuntimeBinderException)
{
return null;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With