2

I am new to programming to kindly bear me. I using c sharp, .net 4, VS 2010

I have a interface class called IHandler with method IsValidate(). I have a message like AMOUNT 50 22.4, where AMOUNT is identifier. So format of messages can be like FLOW 12 33 23.1, again where FLOW is identifier.

Now, based on the identifier i have different classes like ( I have around 15 - 20 classes like this, as i have to validate different message formats and sequence)

  1. AmountValidator

  2. FlowValidator

In these classes i have implementation of IsValidate() method, as these implement IHandler class.

Now my question is, once i identify the identifier of my message like AMOUNT or FLOW i want to create instance of the class.

What is the best way to do this?( I don't want to create 30 instances in, if else statement )

Appreciate any help.

jeroenh
  • 26,362
  • 10
  • 73
  • 104
bayyinah
  • 139
  • 1
  • 3
  • 12

3 Answers3

3

You can do it like so:

IHandler handler = (IHandler)Activator.CreateInstance("assemblyname", "typename");
handler.IsValidate();

The assembly name can be found on the properties page on the project where the handlers are.

Here: assembly name

You also have to remember that everything is case-sensitive, so the typename argument can't be AMOUNTValidator if the class is actually named AmountValidator.

EDIT: Factory sample:

public static class HandlerFactory {
    private static Object factoryLock = new Object();
    private static List<IHandler> handlers = null;

    public static IHandler Gethandler(String type) {
        if (handlers == null) {
            lock (factoryLock) {
                if (handlers == null) {
                    IEnumerable<Type> types = typeof(HandlerFactory).Assembly.GetTypes().Where(t => t.GetInterfaces().Contains(typeof(IHandler)));
                    handlers = types.Select(t => (IHandler)Activator.CreateInstance(t));
                }
            }
        }
        return handlers.Where(h => h.Type == type);
    }
}

public interface IHandler {
    String Type { get; }
    Boolean IsValid(String data);
}
Steen Tøttrup
  • 3,755
  • 2
  • 22
  • 36
  • Hi Steen, Can you kindly explain what do you mean by 'assembly name can be found on the properties page on the project where the handlers are'. Appreciate if you can put some code. – bayyinah Jul 27 '12 at 11:41
  • @bayyinah: right-click on the project; select Properties; in the Application tab there will be a box labelled "Assembly name". That's what you need to put as the first argument to SteenT's `CreateInstance` code – Carson63000 Jul 27 '12 at 11:47
  • Hi Steen, All my classes are in the same application. I don't have them as dlls( i guess from above i interpret my AmountValidator be compiled into dll and reference in project) Is it??. I tried IHandler handler = (IHandler)Activator.CreateInstance("validation", "AmountValidator"); here 'validation' is my application name, i get error couldn't load AmountValidator assembly. All my classes like AmountValidator.cs and FlowValidator.cs are in the same application. Can you kindly advise – bayyinah Jul 27 '12 at 12:17
  • If your project is a class library, it is turned into a dll, if it's a command line or windows form application, it ends up as an exe. Either way, you should find the assembly name of the project containing the handler classes (AmountValidator, FloatValidator, etc.). – Steen Tøttrup Jul 27 '12 at 12:21
  • Hi Steen, Sorry for bothering you. i managed to created handle object like IHandler handler = (IHandler)Activator.CreateInstance("Validation", "Validation.AmountValidator").Unwrap(); After this, how can i proceed. How can i call the IsValidate() method of AmountValidator class? – bayyinah Jul 27 '12 at 12:59
  • It's not a bother! Why the call to UnWrap? And how do the handlers validate anything? Does the IsValidate() method take any parameters? Or does the constructor of the handlers take parameters? – Steen Tøttrup Jul 27 '12 at 13:00
  • I was getting this error.Unable to cast object of type 'System.Runtime.Remoting.ObjectHandle' to type 'Validation.IHandler. So i looked up online and found it. I am able to validate the specific IsValidate(message) method of the class which is passed. Yes it takes string as input. Instead of passing type as "Validation.AmountValidator" i am thinking of placing identifiers along with types "Validation.AmountValidator" in app.config. Is it right design wise or is there some better approach. – bayyinah Jul 27 '12 at 13:13
  • Uhm, this is getting complicated, I would make a change to the interface, so it had a String property that would return the type is handles, like "FLOAT" or "AMOUNT", etc. Then use factory (with reflection) to find all classes with the IHandler interface, and whenever you have a "FLOAT" or "AMOUNT" or whatever, ask the factory for the type matching. Let me make a small sample in the original answer. – Steen Tøttrup Jul 27 '12 at 13:20
2

A factory implementation where you should list your validators once in the constructor, assuming the validators are stateless :

    public class HandlerFactory
{
    private Dictionary<string, IHandler> _handlers = new Dictionary<string,IHandler>();

    public HandlerFactory()
    {
        _handlers.Add("AMOUNT", new AmountValidator());
        _handlers.Add("FLOW", new FlowValidator());
    }

    public IHandler Create(string key)
    {
        IHandler result;
        _handlers.TryGetValue(key, out result);
        return result;
    }
}

Let me know if you want me to elaborate with Reflection and IoC. That would change the way you initialize the dictionary.

Seb
  • 2,637
  • 1
  • 17
  • 15
  • Thanks Seb, i would appreciate if you show Reflection and IoC as well. – bayyinah Jul 27 '12 at 14:02
  • Hi Seb, i was trying your implementation as well. I added identifier and class in app.config as shown below
    and in my code did something like this ' if (settings != null) { foreach (string key in settings.AllKeys) {_handlers.Add(key.ToString(), settings[key].ToString());
    – bayyinah Jul 27 '12 at 18:31
  • How can i add both these values in my dictionary? The code above is wrong when i am adding to dictionary. Can you kindly advise? – bayyinah Jul 27 '12 at 18:34
  • For the reflection based implementation, look at SteenT's answer. – Seb Jul 30 '12 at 08:51
  • You must add a value of the specified type in the dictionary : `IHandler`. In your sample, you're trying to add a pair of (string, string) instead of (string, IHandler). Try to create IHandler instances from the values in the `appSettings` – Seb Jul 30 '12 at 08:59
1

If all your IHandler classes are contained in the same assembly as your application (not dynamically loaded like plugins), Factory method pattern could be a good choice. You can centralizes the creation of IHandler classes with this design pattern. If, on the other hand, the IHandler classes are loaded at runtime, you need to take advantage of .NET Reflection. There are also open source IoC containers that can help with object creations, but I guess they are a bit of an overkill.

Jiaji Wu
  • 459
  • 3
  • 10
  • For a beginner, this might not be very useful on a short term need ;-) But I like it ! +1 – Seb Jul 27 '12 at 13:10