Click here to Skip to main content
15,885,760 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
Hi,

I wrote a factory for some xml parser classes (one for each supplier). The parser classes implemented an interface and the factory would simply call the parser classes method. Here is my factory class:

C#
public static class FlightDataFactory<T> where T : Interface.IFlightDataWorker, new()
{
    public static FlightData.Model.Flight GetFlightData(string flightId)
    {
        T t = new T();
        return t.GetFlightData(flightId);
    }
    public static List<FlightData.Model.Flight> GetFlightData()
    {
        T t = new T();
        return t.GetFlightData();
    }
}

I hope that's all self explanatory.

I now need to load the classes from strings, kept in a db table of suppliers (The reason for this is that we will product-ize this system and only wish to include parsers that are relevant to that client).

I was creating the list of parser methods like this:
C#
private void InitializeWorkers()
{
    flightWorkers = new[]{
        new Worker.FlightServiceWorker(){
            Source = "AirNav",
            GetFlightByIdMethod = FlightData.Factory.FlightDataFactory<FlightData.Worker.AirNavWorker>.GetFlightData,
            GetFlightsMethod = FlightData.Factory.FlightDataFactory<FlightData.Worker.AirNavWorker>.GetFlightData
        },
        new Worker.FlightServiceWorker(){
            Source = "AirNavMock",
            GetFlightByIdMethod = FlightData.Factory.FlightDataFactory<FlightData.Worker.AirNavMockWorker>.GetFlightData,
            GetFlightsMethod = FlightData.Factory.FlightDataFactory<FlightData.Worker.AirNavMockWorker>.GetFlightData
        }
    };
}


My question is: Can I load the classes from a string in such a way as I can use them as types as in the above code, or must I invoke the methods instead.

If I have to invoke them then I guess my factory is a write off

Thanks. Please let me know if I can improve my question before down-voting it ^_^
Posted
Comments
CHill60 20-Feb-15 9:05am    
Would Activator.CreateInstance be useful? https://msdn.microsoft.com/en-us/library/d133hta4(v=vs.110).aspx[^]

I solved this with a new (but not so neat) factory.

If anyone can help me tidy this up then I would be greatful


C#
   public delegate FlightData.Model.Flight GetFlightById(string flightId);
   public delegate List<flightdata.model.flight> GetFlights();
public static class FlightDataFactory
   {
       public static GetFlightById GetFlightByIdDataMethod(Type iFlightDataWorker)
       {
           if (!iFlightDataWorker.GetType().GetInterfaces().Contains(typeof(Interface.IFlightDataWorker)))
               throw new ArgumentException(string.Format("The type {0} does not implement the interface {1}.", iFlightDataWorker.Name, typeof(Interface.IFlightDataWorker).Name), "iFlightDataWorker");

           object worker = iFlightDataWorker.GetConstructor(Type.EmptyTypes).Invoke(new object[]{});

           return delegate(string flightId)
           {
               return (FlightData.Model.Flight)iFlightDataWorker.GetMethod("GetFlightData").InvokeWithExceptions(worker, new object[] { flightId });
           };

       }
       public static GetFlights GetFlightDataMethod(Type iFlightDataWorker)
       {
           if (!iFlightDataWorker.GetType().GetInterfaces().Contains(typeof(Interface.IFlightDataWorker)))
               throw new ArgumentException(string.Format("The type {0} does not implement the interface {1}.", iFlightDataWorker.Name, typeof(Interface.IFlightDataWorker).Name), "iFlightDataWorker");

           object worker = iFlightDataWorker.GetConstructor(Type.EmptyTypes).Invoke(new object[] { });

           return delegate
           {
               return (List<flightdata.model.flight>)iFlightDataWorker.GetMethod("GetFlightData").InvokeWithExceptions(worker, new object[] { });
           };
       }
   }</flightdata.model.flight></flightdata.model.flight>


I have also created a handy Extension method so I get past targetinvocationexceptions which I would hope not to get.
C#
public static object InvokeWithExceptions(this MethodInfo methodInfo, object obj, params object[] parameters)
{
    try
    {
        return methodInfo.Invoke(obj, parameters);
    }
    catch (TargetInvocationException exception)
    {
        if (exception.InnerException != null)
            throw exception.InnerException;
        throw;
    }
}
 
Share this answer
 
Comments
BillWoodruff 20-Feb-15 9:20am    
If that works for you, great ! When you say "productize" I interpret that to mean that each "vendor" gets only a parser specific to their needs: in my mind that means you ship to each "vendor" only a .dll containing their Parser. The conclusion I draw from that interpretation is that you what you need to is load the Parser definition (which includes the required manifest, etc.) as a string from the db at run-time, and then create the Assembly from that string, and then create instances of the loaded Assembly.

If you want a reply here showing how to do that, just ask.
Andy Lanng 23-Feb-15 5:40am    
Hi,
Your interpretation is correct enough. Each client may subscribe to several services to collaborate the data returned. Each service will have it's own parser.
So in this sense, The "vendor" gets only the parsers specific to their needs (or what they pay for, anyway). I have now gone down the path of loading assemblies at run-time but still use delegate methods as above.
I think you would be better served by using a Dependency Injection or Inversion of Control Container such as Microsoft's Unity, NInject, StructureMap, or my Munq IocContainer.

You register the Interface implementations with the container and then either follow the Dependency Injection pattern or Service Locator pattern to get the implementation for the Interface when required.
 
Share this answer
 
Comments
BillWoodruff 21-Feb-15 0:22am    
I'm curious: how would that assist the OP to produce a different version Application for each client that included only the code for the XML parser designed for that client ?
Andy Lanng 23-Feb-15 5:36am    
I too would like to know how I can implement this at run-time. Do you know of any articles? I have searched :S
Thanks

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900