Click here to Skip to main content
15,886,773 members
Please Sign up or sign in to vote.
4.33/5 (3 votes)
See more:
I am struggling with calling a method with reflection...

The method signature is as follows: (changed the actual names...)

I have a interface called :

C#
public interface ICharacteristics
   {
       Score calculateScore(int ScorecardID, string UniqueID, ArrayList CharacteristicsValues);
   }


Then i have another class called:

C#
public class ScoreSmartCharValues
   {
       private string name;
       private int value;

       public int Value
       {
           get { return this.value; }
           set { this.value = value; }
       }

       public string Name
       {
           get { return name; }
           set { name = value; }
       }

       public ScoreSmartCharValues(int value, string name)
       {
           this.name = name;
           this.value = value;
       }

       public ScoreSmartCharValues()
       {

       }
   }


another class as follow:

SQL
public Score calculateScore(int ScorecardID, string UniquesID, ArrayList CharacteristicsValues)
        {

//Do something and return Score;

 return new Score();
}


Ok so once build... generates a DLL score.dll


The code that i use is simple to call reflection and invoke the method:

C#
Assembly assembly = Assembly.LoadFrom(@"Score.dll");


foreach (Type type in assembly.GetTypes())
            {
                // Pick up a class
                if (type.IsClass == true)
                {
                    Console.WriteLine("...Found Class : {0}", type.FullName);

                    // If it does not implement the IBase Interface, skip it
                    if (type.GetInterface("ICharacteristics") == null)
                    {
                        continue;
                    }

                    // If however, it does implement the IBase Interface,
                    // create an instance of the object
                    object ibaseObject = Activator.CreateInstance(type);
                    List<ScoreSmartCharValues> CharacteristicsValues = new List<ScoreSmartCharValues>();
                    CharacteristicsValues.Add(new ScoreSmartCharValues(1, "robs"));

                    object oObjectType = new object();
                    oObjectType = CharacteristicsValues;
                    // Create the parameter list
                    object[] arguments = new object[] { 10, "test", CharacteristicsValues };
                    object result;
                    // Dynamically Invoke the Object
                    Console.WriteLine("......Dynamically Invoking compute() on {0} Class", type.FullName);
               
                    result = type.InvokeMember("calculateScore",
                                                BindingFlags.Default |BindingFlags.InvokeMethod,
                                                null,
                                                ibaseObject,
                                                arguments);

                    Console.WriteLine("......Result is: {0}", result);
                }
            }



I get a method not found...

If i change the argument to send in Null in the place of the list it works...
Posted
Updated 3-Jun-11 2:54am
v3
Comments
BobJanova 3-Jun-11 8:55am    
The reason the bind is failing is that the list type you generate (List<scoresmartcharvalues>) and the one the method accepts (List<Characteristics>) are not compatible. But please see Fredrik's answer and my comment thereunder: you don't need to use runtime binding at all.

I'm not sure, but it looks to me like you don't need the reflection bit at all.
Can't you just cast you ibaseObject to a ICharacteristics and invoke the calculateScore method normally?

If you do need to call it using reflection, here's a working example of what I think you're trying to do:

C#
using System;
using System.Collections;

namespace ReflectionTest
{

    public interface ICharacteristics
    {

        int calculate(int number, string Name, IList Characterstics);
    }

    public class MyImplementation : ICharacteristics
    {
        public int calculate(int number, string Name, IList Characterstics)
        {
            return 42;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            object[] instances = new object[] { "Test", new MyImplementation() };

            foreach (object instance in instances)
            {
                if (instance is ICharacteristics)
                {
                    Type type = instance.GetType();
                    object result = type.InvokeMember("calculate", System.Reflection.BindingFlags.InvokeMethod, null, instance,
                        new object[] { 1, "Name", new ArrayList()});
                }
            }
        }
    }
}


Hope this helps,
Fredrik Bornander
 
Share this answer
 
Comments
BobbyBlueEyes 3-Jun-11 5:41am    
I have to use reflection as the calculate part is in a seperate DLL
BobJanova 3-Jun-11 8:45am    
No you don't. The interface should be defined in the main assembly, or a shared DLL which both the main assembly and the plugins can interface, so you can reference it, even if the implementing class is not defined in this assembly. This is fundamental to a good plugin architecture.

You do -not- need the implementing class to be visible at compile time. Only the interface.

Then you can do:

Assembly assembly = Assembly.LoadFrom(@"name.dll");
foreach (Type type in assembly.GetTypes())
{
// Pick up a class
if (type.IsClass == true)
{
Console.WriteLine("...Found Class : {0}", type.FullName);

// If it does not implement the IBase Interface, skip it
if (type.GetInterface("ICharacteristics") == null)
{
continue;
}

// If however, it does implement the IBase Interface,
// create an instance of the object
ICharacteristics ibaseObject = (ICharacteristics)Activator.CreateInstance(type);
List<Characteristics> CharacteristicsValues = new List<Characteristics>();
CharacteristicsValues.Add(new ScoreSmartCharValues(1, "robs"));

int result = ibaseObject.calculateScore(10, "Test", CharacteristicsValues);
}
}
BobJanova 3-Jun-11 8:53am    
5 for better higher level advice.
BobbyBlueEyes 3-Jun-11 9:07am    
Ok i have updated the solution....

I cannot cast to ICharacteristics - what am i missing here?
BobbyBlueEyes 3-Jun-11 9:33am    
ok got i working BobJanova you where absolutely right - should have followed the basic architecture best parctices.
Hi,

I would suggest to use dynamic where you find GetType() kind of code. Will give better performance too.

Soultion:

In this line
VB
// If however, it does implement the IBase Interface,
// create an instance of the object
object ibaseObject = Activator.CreateInstance(type);


instead of taking it as an object type above. Please use dynamic type as below and calling will simpler and better for sure.

MIDL
dynamic ibaseObject = Activator.CreateInstance(type);</pre>


Now,

Call whatever you want will be so easy and better in performance.

EX: ibaseObject.calculate(5, "name", arguments);

In above code, Like any other class object you can call those methods of class without any invoke method of reflection here.

Sure this will help you in reflection.

Hope this will help you

For more Information Please refer below link :

Perform Reflection and XML Traversing Using the dynamic Keyword in C#[^]


Thank You :)
 
Share this answer
 
v2
Comments
BobbyBlueEyes 3-Jun-11 5:49am    
Hi Thanks for the help,

But if i send in a List i still get the error, if i send in a null value then the method does get executed....
BobJanova 3-Jun-11 8:52am    
dynamic still uses similar runtime binding methods under the covers to Reflection, so it doesn't really solve the problem, although it does make reflection-based code cleaner in the source.
Something like this?

C#
class Program {
    static void Main(string[] args) {

        List<ScoreSmartCharValues> characterstics = new List<ScoreSmartCharValues>();
        characterstics.Add(new ScoreSmartCharValues(1, "Hello"));
        characterstics.Add(new ScoreSmartCharValues(2, "World"));

        DoSomethingUsefull doSomethingUsefull = new DoSomethingUsefull();

        var methodToCall = doSomethingUsefull.GetType().GetMethod(
            "calculate",
            new Type[] {
            typeof(int),
            typeof(String),
            typeof(List<ScoreSmartCharValues>)
        }
        );
        methodToCall.Invoke(doSomethingUsefull, new Object[] { 1, "Foobar", characterstics });
        Console.WriteLine("Done");
        Console.ReadLine();
    }

}

public class DoSomethingUsefull {

    public int calculate(int number, string Name, List<ScoreSmartCharValues> Characterstics) {

        Console.WriteLine(number);
        Console.WriteLine(Name);
        foreach (var characterstic in Characterstics) {
            Console.WriteLine("{0} -> {1}", characterstic.Name, characterstic.Value);
        }

        return 0;

    }


}

public class ScoreSmartCharValues {
    private string name;
    private int value;

    public int Value {
        get { return this.value; }
        set { this.value = value; }
    }

    public string Name {
        get { return name; }
        set { name = value; }
    }

    public ScoreSmartCharValues(int value, string name) {
        this.name = name; this.value = value;
    }

    public ScoreSmartCharValues() { }
}
 
Share this answer
 
v2
Comments
BobbyBlueEyes 3-Jun-11 6:34am    
The List being sent is of type class - that contains a int and a string as properties.
StM0n 3-Jun-11 6:58am    
Sorry, I'm not quite sure what you mean. Did you mean the IList?
BobbyBlueEyes 3-Jun-11 7:55am    
please see my code below:

public class ScoreSmartCharValues
{
private string name;
private int value;

public int Value
{
get { return this.value; }
set { this.value = value; }
}

public string Name
{
get { return name; }
set { name = value; }
}

public ScoreSmartCharValues(int value, string name)
{
this.name = name;
this.value = value;
}

public ScoreSmartCharValues()
{

}
}


I create a List of this type.

so this is my method signature:

Score calculateScore(int ScorecardID, string UniqueID, List<scoresmartcharvalues> CharacteristicsValues);


When i try to use reflection i cannot call the method...

I have change the signature to rather use a type of type object then it works fine...
StM0n 3-Jun-11 8:07am    
Changed my solution...
StM0n 3-Jun-11 8:29am    
Oops... now I see your Problem:

You do...

object oObjectType = new object();
oObjectType = CharacteristicsValues;

object[] arguments = new object[] { 10, "test", CharacteristicsValues };


but the signature of your method is...
public int void calculate(int number, string Name, List<characteristicsvalues> Characterstics)

Your invoke does not match the signature of the method you want to call...

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900