tags:

views:

89

answers:

5

1st Question:

In PHP there is:

$b = new SomeClass();
$a = "foo";
$b->$a("something"); // This is the same as $b->foo("something");

How do you do this in C#?


2nd Question:

In PHP I can iterate through each method on a class, similar to:

$a = new SomeClass(); // Which implements methodA, methodB;
foreach($method in get_class_methods(SomeClass()))
{
  $method("do stuff with each method");
}

How to do this in C#?


3rd Question

PHP has a magic method __call() if a Class does not implement a method it executes it as a default such as if a method doesn't exist it still can run

class NewClass()
{
// constructor

__call(class name, array of parameters)
{

}
}

so if you do

$a = new NewClass();
$a->thisDoesntExistButWorks("123","abc");

// The method gets "magically created"  such as
thisDoesntExistButWorks(array with 123 and abc)....
+1  A: 
  1. Delegates is the closest thing I can think of (Control.Invoke()).

  2. You could get them using Refection (Type.GetMethods())

  3. You can create a dynamic method. In PHP __call() is not very useful unless you define what it does anyways.

That being said I would avoid doing stuff like this (even in PHP).

NullUserException
+4  A: 

None of your PHP functionality is AS elegantly implementable in C#, but except for the third they're all possible.

1:

var b = new SomeClass();
var a = "Foo";
b.GetType().GetMethod(a).Invoke(b, /*object[] of parameters*/);

2:

var a = new SomeClass();

foreach(MethodInfo mi in a.GetType.GetMethods())
{
   /*do something with method using mi*/
}

You can implement an extension method ForEach() in 3.5 (may be available in 4.0's Linq library) to turn this into a method chain; the code in the curly braces would become a lambda.

AFAIK, #3 is not possible in any built-in fashion in C#. You would work around it by trying to call the method reflectively in a try block, catching any TargetExceptions that are thrown when the call fails, and implementing your default behavior in the catch.

KeithS
A: 

Here's a few resources based upon reflection for calling methods dynamically:

Reflection and Dynamic Method Invocation

Dynamic Method Invocation in C# using Reflection

ircmaxell
A: 

1st

var method_name = "my_method"
// you can change the null by the parameters you need
my_object.GetType().GetMethod(method_name).Invoke(my_object, null);

2nd

MethodInfo[] methodInfos = typeof(MyClass).GetMethods();

foreach (MethodInfo methodInfo in methodInfos)
{
    /* doing stuff... */
}

3rd

I don't know how you can do something like in C#, but if you tell your problem, sure there will be a workaround for that.

Alaor
+1  A: 

1 and 2 have been answered more than once. So i'll attempt 3.

C# does not provide an unknown method method because it doesn't have to. If you call the Method directly like a.NonExistentMethod() then the program simply wont compile, and the idea of catching the bad call at runtime is irrelevant.

As you have already found out though it it possible to call methods dynamically at runtime by doing a.GetType().GetMethod("NonExistentMethod").Invoke(a, new object[0]). This will fail with a NullReferenceException because the call to GetMethod returns null. However this situation is detectable, and so maybe we can do something about it. Here is an extension method that behaves as much like PHP as possible. Please note that this is untested, and should never be used in production (or probably even experimental) code.

This can by used by doing this a.CallOrDefault("method name", arg1, arg2);

public static class PhpStyleDynamicMethod
{
    public static void __call(Type @class, object[] parameters)
    {
        // Do stuff here.
    }

    public static object CallOrDefault(this object b, string method, params object[] parameters)
    {
        var methods = b.GetType().GetMethods().Where(m => m.Name == method && DoParametersMatch(m.GetParameters(), parameters));

        var count = methods.Count();

        if (count == 1)
            return methods.Single().Invoke(b, parameters);

        if (count > 1)
            throw new ApplicationException("could not resolve a single method.");

        __call(b.GetType(), parameters);

        return null;
    }

    public static bool DoParametersMatch(ParameterInfo[] parameters, object[] values)
    {
        if (parameters == null && values == null) return true;
        if (parameters == null) return false;
        if (values == null) return false;
        if (parameters.Length != values.Length) return false;

        for(int i = 0; i < parameters.Length; i++)
        {
            var parameter = parameters[i];
            var value = values[i];

            if (!parameter.GetType().IsAssignableFrom(value.GetType()))
                return false;
        }

        return true;
    }
}
Jack Ryan