4

I'm changing a processing algorithm I've made from reflection to delegate since it handles huge data and it is having performance issues(as I have learned here). So my old code is a simple reflection as shown below:

var result = method.Invoke(service, new object[] { viewModel });

Where the method is a MethodInfo, service is a service class with a common method called Add(). All services have that method(not generic tho) and this processing algorithm can run over any service, hence, service(the instance) is dynamic. It is resolved with Unity.

Here is a working demo with a similar code that I'm trying to make happen:

using System;
using System.Reflection;

// This is the delegate declaration
public delegate string ServiceDelegate(ViewModel vm);

public class Program
{
    public static void Main()
    {
        // Here the 'Service' class is created by a IoC container
        object service = DependencyInjectionSimulator.Resolve();
        Type type = service.GetType();
        MethodInfo method = type.GetMethod("Add");

        ServiceDelegate serviceDelegate = (ServiceDelegate)Delegate.CreateDelegate(typeof(ServiceDelegate), service, method);

        var car = new CarViewModel();

        Console.WriteLine(serviceDelegate(car));
    }
}

// This is the 'Service' base class. It will be created dynamically and all services has the Add() method with a 'ViewModel' inherited class
public class Service
{
    public string Add(CarViewModel input)
    {
        return input.Name;
    }
}

// All 'Add()' method of services will work with a parameter that inherits 'ViewModel'
public class ViewModel
{
    public string Name { get; set; }
}

public class CarViewModel : ViewModel
{
}

// Let's pretend this is a Unity Resolver
public static class DependencyInjectionSimulator
{
    public static object Resolve()
    {
        return new Service();
    }
}

I hope this clarifies with I'm trying to achieve, although I'm not sure if it is possible.

Keyur Ramoliya
  • 1,900
  • 2
  • 16
  • 17
DontVoteMeDown
  • 21,122
  • 10
  • 69
  • 105
  • I don't get why you need reflection or delegates at all. The `DependencyInjectionSimulator.Resolve` method should return the correct type in the first place meaning you can call methods on it as you would call any other object. – DavidG Jul 12 '18 at 12:24
  • @DavidG It doesn't. The resolver in this case returns an object, I can't call `.Add()` in an object, right? Or there is something that I'm missing? – DontVoteMeDown Jul 12 '18 at 12:33
  • But I'm saying your DI simulator here doesn't mimic how a *real* DI service would work. – DavidG Jul 12 '18 at 12:34
  • @DavidG probably. But it is the closest I could get to a real DI service. In fact the error is the same I'm getting in my real code, so it seems pretty close. There is a better way to mimic a real DI behaviour in that fiddle? – DontVoteMeDown Jul 12 '18 at 12:37

1 Answers1

1

Your DI framework will only ever give you an object that represents the type you are asking for, so you shouldn't ever need to worry about delegates or reflection. For example, let's update your DI simulator to this:

public static class DependencyInjectionSimulator
{
    public static TService Resolve<TService>() 
        where TService : class
    {
        //So this only works for the one type right now, but hey, it's only a simulator!
        return new Service() as TService;
    }
}

I would also suggest you use an interface for your service, it's a good habit to get into and it will help in future with things like unit testing:

public interface IService
{
    void Add(CarViewModel input);
}

public class Service : IService
{
    public void Add(CarViewModel input)
    {

    }
}

Now your code simplifies to this:

var service = DependencyInjectionSimulator.Resolve<IService>();
var car = new CarViewModel();
service.Add(car);
DavidG
  • 113,891
  • 12
  • 217
  • 223
  • 1
    I have that option but I can't do like that. My scenario is this: I have hundreds of services, which have `Add()` but the view model changes on each `Add()` method. In that proccess, I only have the name of the service as an string, that is why I use reflection in first place. I create an instance of that viewModel with `Actvator.CreateInstance` and call `Invoke` on the service's `Add()` method with that view model. Everything is dynamic, that is why I can't use the generic resolver. Please let me know if something is not clear yet. – DontVoteMeDown Jul 12 '18 at 12:43
  • It looks like there's something very wrong with your implementation then but without known much more about your code base, there's not much else I can say. I find it peculiar because in the code above you know the type of the model, so it's not a huge jump to then include that in the resolver too. – DavidG Jul 12 '18 at 12:47
  • The model type is fixed in the example but it it not in the original code. Everything is dynamic: resolving the service is made with it's type which I recover by reflection; the viewModel is create with `Activator.CreateInstance` and dynamicly populated prior to be passed to the service's `Add()` method by `Invoke`. The processing is a dynamic import tool which gathers data from another base and includes in the target database by that processing. – DontVoteMeDown Jul 12 '18 at 12:57