Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duck type testing with C# 4 for dynamic objects

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
}
like image 874
Tracker1 Avatar asked Jun 06 '10 17:06

Tracker1


People also ask

Does C++ have duck typing?

Up to you whether you define "duck typing" so that this difference means C++ doesn't have it.

What languages use duck typing?

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.

What is duck typing in C#?

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.

Why is duck typing called duck typing?

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.


2 Answers

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.

like image 87
Andrew Anderson Avatar answered Sep 21 '22 10:09

Andrew Anderson


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;
        }        
    }
like image 35
Simon Avatar answered Sep 19 '22 10:09

Simon