Object Oriented Dilemma

Posted on 2004-04-24
Last Modified: 2010-04-24
I have a flowchart drawing tool that enables me to draw boxes and the capability to assign an object to each box. In my program, I have a number of functions and subs that perform tasks. And I enable the user to assign these functions to the box.

As an example, in our program we have three functions: copyfile, movefile, and deletefile. Copyfile and movefile have parameters of SourcePathAndName and DestPathAndName, while deletefile only requires a parameter of SourcePathAndName. Each of functions returns a boolean result of success or failure of the copy, move, or delete.

The question is, what is the smart way to design this program so that as I add additional functions (and there will be many more) I can smartly manage the hooks to my "presentation layer" and "execution layer" with the minimum number of steps.

Currently I declare a string array of functions which I load programmatically, replicating the functions I have already created that I want the user to use (in our example, copyfile, movefile, and deletefile). Then at "the other end of the program" where I actually perform the activity (copy, move, or delete the file) I look at the box object and the function assigned to it, do a "select case" based on the assigned function, and call the appropriate function.

My approach works, but whenever a new function (capability) is added, I have to add that function to my "functions array" so my user will be able to see it and assign it to a box. And in my execution routine, I have to add another case statement to call it. It seems like there must be a smarter approach.

I have looked at the programming techniques of reflection and also creating a delegate (to directly execute the function rather than using a series of case statements). Both of these techniques appear promising, but alas I'm not sure if they are applicable to this dilemma.

The best suggestion and sample of how to approach this wins the points. Thank you!
Question by:wparrack
LVL 27

Expert Comment

ID: 10913686
Hi wparrack:
Lets make it easier for us to help you by clarifying your problem.
Could you choose one of the three functions and post snippets of code as to what you have done?
It might make it easier for us to show you how we would approach the same problem

LVL 37

Accepted Solution

gregoryyoung earned 500 total points
ID: 10914127

make an interface ...

IApplicationCallableObject {
    ParameterCollection RunFunction(ParameterCollection _Arguments) ;
    ParameterCollection QueryRequiredParameters() ;
    //etc etc
    //maybe add some stuff here to allow custom property dialogs etc i.e.
    Form CustomPropertyDialog { get; };

example class

public class DeleteFile : IApplicationCallableObject {
     ParameterCollection RunFunction(ParameterCollection _Arguments) {
           if(_Arguments == null || _Arguments.Count == 0 || !_Arguments.Contains("Filename") {
                throw new System.Exception("Required Parameter Filename missing") ;
           File.Delete(_Arguments["Filename"]) ;
           return null ;
           //this is actually a sub ... to return you would add values to a parameter collection and return it.

     ParameterCollection QueryRequiredParameters() {
          ParameterCollection ret=new ParameterCollection() ;
          ret.add(new Parameter("Filename", typeof(string)) ;
          return ret ;

in your main code you load them all up into an array or typed collection of IApplicationCallableObjects ... then you just build the parameter array and call ParameterCollection ReturnValues = object.RunFunction(Parameters). This will also allow you to pass multiple values back and forth (or you can just modify the parameter collection given to you to add return values etc) ...

You could very easily make it so that the user tells you to load up say 9 .dlls dynamically (or all in 1 directory etc etc) you then just get all objects that implement this interface and set them as your available objects (You use CreateInstance to do this). The big difference here in comparison with what you are currently doing is that this allows you to add functionality without changing the original code (or even having access to the original code so your end users could actually create their own if they wanted ... just add their own dll to the ones you load :) )


Expert Comment

ID: 10918118
I believe using Relfection is your way to go.  I just wrote a class testing application that required me to use just about everything in System.Reflection.  The classes you will use most often are System.Reflection.MethodInfo, System.Reflection.ParameterInfo, and System.Type  

I see two possible scenarios...

1.)  All your functions are contained in one class

2.)  Your functions are contained in 2 or more classes.

Here are the basic steps you will need to follow...

1.)  Load the assembly that contains your functions.  If they are in your current project solution, they will automatically be loaded.  If they are separate project, you will need to load them at run-time using Assembly.LoadFrom()

2.)  You will then need to list the list of functions using System.Type and its function GetMethods()

3.)  Once the function is selected and parameters values determined, use Activator.CreateInstance to create an instance of the class.  If you want to use something more than the default constructor, ask me and I'll show you how.

4.)  Then create an object array that holds the parameters and use MethodInfo.Invoke to call the actual function.

I used the .Net Framework SDK to learn all this that might be a good place to start.  

If you want me to post some code samples to help you along just let me know.
Complete VMware vSphere® ESX(i) & Hyper-V Backup

Capture your entire system, including the host, with patented disk imaging integrated with VMware VADP / Microsoft VSS and RCT. RTOs is as low as 15 seconds with Acronis Active Restore™. You can enjoy unlimited P2V/V2V migrations from any source (even from a different hypervisor)

LVL 37

Expert Comment

ID: 10918234
why would you loosely type everything through reflections as opposed to just using a strongly typed interface which describes what a plugin can do and just searching for objects which support the interface ?

Expert Comment

ID: 10918390
Why not?  Both ways work.  It depends on what wparrack wishes to do.  I personally would use relfection.  He knows better what he is trying to accomplish and how the requirements may change in the future.  If nothing else, I am giving him another option.
LVL 37

Expert Comment

ID: 10919801
The only time I can see leaving a strongly typed system is if a requirement was set to be abe to call methods of existant framework items etc directly or without wanting to write a wrapper for them.

I say this for a few reasons.

1) You have far less control over the non-strongly typed system (especially when dealing with issues like thread safety)

2) the strongly typed system offers more functionality and higher flexibility for future flexibility i.e. using the strongly typed system you can include custom dialogs for configuration of the plugin or include further information as to what it can do (example: a description of what it can do and a link to a help file)

3) The code is simpler to deal with in the strongly typed method

4) An outside developer is handed a clear contract with the strongly typed method

5) Using the strongly typed method you end up with a very clean result (A directory that contains one or may .dlls which are just loaded at runtime. to add more just drop in more .dlls).

6) You can write a generic loading/metadata system using the strongly typed system that you can reuse for all your future plugin needs (factory and decorator patterns come to mind).

7) This is probably the biggest issue I have with the reflections method: You often times end up in very complex situations configuration wise to do something very simple.

Ex: Lets say I have a singleton object that maintains some values (ill use the example of stock quotes that it refreshes from a server in a seperate thread). I want to call a method which gets will look up my quote and return the price. I now need to support the ability to call the member which returns the instance and then goes and calls the instance member of this ... Its very easy to call a single function using reflections but allowing you to define and string together multiple calls becomes much more difficult. There is the easy solution of writing a wrapper function which does this but I have already discussed not having to write a wrapper as being one of the reflection methods largest advantages.

Given all of this I will finally point out that this is how Microsoft does it in .net --- IComponent


Expert Comment

ID: 10920324
You bring up some very good points and I agree with you.  The strongly typed system would be a better fit in this situation.  You seem to have a more in depth understanding of .Net than I do yet.  Thanks for the full, clear explanations.  

Author Comment

ID: 10924485
Thank you to all who responded. gregoryyoung gets the points, as it directly addresses my problem (and I even understand the solution! (smile)). And it opens the door to managing 3rd party dll's which I would also like to do. You guys are good!!!

Featured Post

Ransomware: The New Cyber Threat & How to Stop It

This infographic explains ransomware, type of malware that blocks access to your files or your systems and holds them hostage until a ransom is paid. It also examines the different types of ransomware and explains what you can do to thwart this sinister online threat.  

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

If you're writing a .NET application to connect to an Access .mdb database and use pre-existing queries that require parameters, you've come to the right place! Let's say the pre-existing query(qryCust) in Access takes a Date as a parameter and l…
It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that unde…
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.
Although Jacob Bernoulli (1654-1705) has been credited as the creator of "Binomial Distribution Table", Gottfried Leibniz (1646-1716) did his dissertation on the subject in 1666; Leibniz you may recall is the co-inventor of "Calculus" and beat Isaac…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question