Extract from the DRP … “Using an interface instead of InvokeMethod with Reflection” - Willy-Peter Schaub's Cave of Chamomile Simplicity

Extract from the DRP … “Using an interface instead of InvokeMethod with Reflection”

We are told that InvokeMethod with Reflection is slow and that we should be using an interface. But how … the example ProcessData either calls ComplexReflection (using InvokeMethod) or SimpleReflection (using an interface).

 

#define Neptune

 

using System;

using System.Reflection;

using System.Runtime.Remoting;

using System.Globalization;

using System.Diagnostics;

 

 

namespace BBD.Drp.Remoting

{

    [RefClass("BBD.Drp.Remoting.CalculationA.dll",

              "BBD.Drp.Remoting.CalculationA",

              false)]

    public class RemoteObject : MarshalByRefObject

    {

        private DateTime dateTimeStart = DateTime.Now;

        private DateTime dateTimeEnd;

        private long     processTime;

   

        public RemoteObject()

        {

        }

 

        public bool ProcessData ( double valueOne, double valueTwo,

                                  out double result, out string description )

        {

            bool success     = false;

            result           = 0;

            description      = "Unknown";

 

            // Check our attributes

            Attribute[] attrs = Attribute.GetCustomAttributes(typeof(RemoteObject));

            foreach ( object attr in attrs )

            {

                if ( attr is RefClass )

                {

                    if ( ((RefClass)attr).complex )

                    {

                        success = this.ComplexReflection ( ((RefClass)attr).name, ((RefClass)attr).cclass,

                            valueOne, valueTwo, out result, out description );

                    }

                    else

                    {

                        success = this.SimpleReflection ( ((RefClass)attr).name, ((RefClass)attr).cclass,

                            valueOne, valueTwo, out result, out description );

                    }

 

                    dateTimeEnd = DateTime.Now;

                    // Calculate difference between end and start in milliseconds

                    processTime = (long) ((TimeSpan)(dateTimeEnd - dateTimeStart)).TotalMilliseconds;

                }

            }

 

            return ( false );

        }

 

        private bool ComplexReflection( string dll,        string cclass,

                                        double valueOne,   double valueTwo,

                                        out double result, out string description )

        {

            // init

            double retCode;

            result      = 0;

            description = "";

 

            // Load DAO using reflection

            Assembly assembly = Assembly.LoadFrom( dll );

                   

            // Load Type within Assembly

            Type     type       = assembly.GetType( cclass, true, true );

            CultureInfo culture = new CultureInfo( "en" );

                    

            // Create an instance of a type.

            object[]     argsConstructor    = { "Add Calculation" };

            object       objectCalculator   = null;

                         objectCalculator   = type.InvokeMember( null,

                                                                 BindingFlags.DeclaredOnly |

                                                                 BindingFlags.Public   | BindingFlags.NonPublic |

                                                                 BindingFlags.Instance | BindingFlags.CreateInstance, null, null,

                                                                 argsConstructor, culture );

           

            // Call Method

            object[]     arguments    = { valueOne, valueTwo, result, description };

            retCode = (double)type.InvokeMember( "Calculate",

                                                 BindingFlags.Instance

                                                 | BindingFlags.InvokeMethod

                                                 | BindingFlags.Public,

                                                 //| BindingFlags.NonPublic, // Needed to access private

                                                 null, objectCalculator, arguments, culture );

            result      = (double)arguments[2];

            description = (string)arguments[3];

 

            return true;

        }

 

        private bool SimpleReflection( string dll, string cclass,

                                       double valueOne, double valueTwo,

                                       out double result, out string description)

        {  

            // init

            double retCode;

            result                          = 0;

            description                     = "";

            object[]     argsConstructor    = { "Add Calculation" };

           

            // Load DAO using reflection

            Assembly    assembly   = Assembly.LoadFrom( dll );

            Type        type       = assembly.GetType( cclass, true, true );

            ICalculator calc       = (ICalculator)Activator.CreateInstance( type, argsConstructor );

           

            retCode = calc.Calculate ( valueOne, valueTwo, out result, out description );

            return true;

        }

 

        [Conditional("Neptune")]

        private void Whatever ()

        {

        }

    }

}

 

 

If you have a better way of solving the issue, please let us know.

 

Published Monday, November 22, 2004 7:38 PM by willy
Filed under:

Comments

# RE: Extract from the DRP … “Using an interface instead of InvokeMethod with Reflection”

Monday, November 22, 2004 9:37 PM by pieter@psh.co.za (Pieter Jansen van Vuuren)
I'm for the Interface bit!

It's way simple, compared to the complex version, and should be a lot easier to maintain.

# re: Extract from the DRP … “Using an interface instead of InvokeMethod with Reflection”

Wednesday, November 24, 2004 12:31 AM by MaLio
A few thoughts in answer to your question ...

A factory object supplying relevant calculators - best way.

Here you are hard coding dll names, you might as well set a reference and do without reflection entirely.

If you are going to dynamically load dll's be sure to handle the AssemblyResolve event from your AppDomain. Also, these assemblies you are loading into the appdomain, cannot be unloaded.

(also to take care that the dll versions of the runtime loaded dll is the same at all locations (if you are using the class both remotely and locally) since the behaviour may change between local usage and remote usage)

If you are going to require the calculator for multiple calculations, retain a reference to the (probably here System.Refelection.MethodInfo instead of type.InvokeMember), then you only need to perfom the most of the reflection task the first time, only needing to call the invoke method on subsequent calculations.
Also if you make the calculation method static (which seems quite possible here, but cannot tell by the code alone) you no longer need to call the constructor to create the instance.

# re: Extract from the DRP … “Using an interface instead of InvokeMethod with Reflection”

Wednesday, November 24, 2004 10:50 AM by Willy
MaLio,

I agree with all your comments.

The code is not production code, just example code from DRP material to illustrate the difference between using InvokeMethod and an interface based approach. Therefore you will not find the fluff, i.e. class factory, dynamioc configuration, or version management which is absolutely required in real-life, but would draw attention from the "eye of the topic".

Thanks for your feedback.
Willy

Leave a Comment

(required) 
(required) 
(optional)
(required) 

Enter the numbers above: