tags:

views:

219

answers:

2
public interface IProcessor<T>
{
  void Process(T instance);
}


foreach(AbstractType instance in myClass.SomeCollection)
  OnProcess(instance);

public void OnProcess<T>(T instance)
{
  IProcessor<T> processor = 
    unityContainer.Resolve<IProcessor<T>>();
  processor.Process(instance);
}

The problem with this code is that the in OnProcess is always AbstractType, and not the concrete type of the instance being passed. I currently see two possibilities.

01: Create a non generic IProcessor and use it as the base for IProcessor. Any implementor will have to implement both generic and non-generic Process methods, typically typecasting and passing onto the generic method.

02: Use Type.MakeGenericType to get the IProcessor, resolve that, and then use reflection to invoke the Process method.

Both of these approaches feel a bit "unclean". Can anyone think of a way I can do this without having to resort to these practices?

Thanks

Pete

A: 

If I understand your problem, you want to call a process that's dependent on 2 types (the type of processor, and the object being processed). Is that right? If that's the case, you can use a multi-method pattern for this kind of problem. Here's an example:

public interface IProcessor
{
    void Process( IThingToProcess p ); // Will call p.ProcessMe()
    void Process( ThingToProcess1 concreteP ); // Called back from ThingToProcess1.ProcessMe
}

public interface IThingToProcess
{
     void ProcessMe( IProcessor p );
}

public class ThingToProcess1 : IThingToProcess
{
    public void ProcessMe( IProcessor p ) { p.Process( this ); }
}
Andy
+2  A: 

2 will be a performance killer (the necessary dynamic/relection invoke in particular is slow)

1 is a common answer to this problem, especially with explicit implementation; the problem is getting hold of the type... does unity allow query with a Type instance, rather than via generics? If so something like below... of course, you might still have to use MakeGenericType:

Type intType = typeof(IProcessor<>).MakeGenericType(instanceType);
IProcessor proc = (IProcessor) IoC.Resolve(intType);

Where instanceType is perhaps via instance.GetType(). For similar reasons, it might be helpful to expose the T as a Type on the IProcessor:

public interface IProcessor
{
    void Process(object instance);
    Type InstanceType {get;}
}
public interface IProcessor<T> : IProcessor
{
    void Process(T instance);
}
class SomeClass: IProcessor<int>
{
    public void Process(int instance)
    {
        throw new NotImplementedException();
    }
    Type IProcessor.InstanceType {get {return typeof(int);}}
    void IProcessor.Process(object instance)
    {
        Process((int)instance);
    }
}

Of course, an (optional) base-class might allow you to avoid some of this per-implementation:

abstract class SomeBase<T> : IProcessor<T>
{
    public void Process(T instance)
    {
        OnProcess(instance);
    }
    Type IProcessor.InstanceType {get {return typeof(T);}}
    void IProcessor.Process(object instance)
    {
        Process((T)instance);
    }
    protected abstract void OnProcess(T instance);
}
Marc Gravell
I've only just managed to get around to logging back into this site. It's funny that your SomeBase<T> suggestion is exactly what I came up with this morning when emailing with Mr Skeet on the subject :-)Thanks!
Peter Morris
How do I mark your answer as the correct one?
Peter Morris
I think you found it ;-p
Marc Gravell