0
votes

Consider the following sample:
I have a Car class and an ILogger interface. I'd like the ILogger implementations to log (console, file, db, etc) a list of cars' specs. And of course, I want to use MEF for ILogger. But for logging, my logger class should have access to a car's specification. And I'm not sure what would be the best way to pass objects to my logger classes. To be more clear, here's some code:

class Program
{
    public class Car
    {
        public string Brand { get; set; }
        public string Model { get; set; }
    }

    private CompositionContainer _container;

    [Import(typeof(ILogger))]
    public ILogger logger;

    private Program()
    {
        var catalog = new AggregateCatalog();
        catalog.Catalogs.Add(new AssemblyCatalog(typeof(Program).Assembly));
        this._container = new CompositionContainer(catalog);
        this._container.ComposeParts(this);
    }  

The ILogger interface should get a Car object for logging. And I'm not sure whether I should pass it in logger's constructor or as a Property, or just a method parameter.

  • Using property: If I use a property for passing a car, the ILogger interface looks like this:
    public interface ILogger
    {
        Car Car { get; set; }
        void Log();
    }
    

    And I can iterate through my list items as below:
    static void Main(string[] args)
    {
        Program p = new Program(); // Composition is performed in the constructor
        var cars = new List()
            {
                new Car() { Brand = "Nissan", Model = "SkyLine" },
                new Car() { Brand = "Porche", Model = "Carrera"},
                new Car() { Brand = "Ferrari", Model = "Enzo"}
            };
        foreach (var car in cars)
        {
            p.logger.Car = car;
            p.logger.Log();
        }
        Console.ReadKey();
    }
    
  • Using parameter: The interface:

    public interface ILogger
    {
        void Log(Car car);
    }
    

    and the program:

    foreach (var car in cars)
    {
        p.logger.Log(car);
    }
    
  • Using constructor: This is where I seem to be lost. I can change the ILogger interface to :

    public interface ILogger
    {
        Car Car {get; set;}
        void Log();
    }
    

    And in the implemented class:

    [Export(typeof(ICarLogger))]
    public class ConsoleLogger : ICarLogger
    {
        public Car Car { get; set; }
        [ImportingConstructor]
        public ConsoleLogger(Car car)
        { 
            this.Car = car;
        }
        public void Log()
        {
            Console.WriteLine("Brand: {0}\tModel: {1}", Car.Brand, Car.Model);
        }
    }
    

But this leads to creating the CompositionContainer everytime I want to pass a new value to the constructor (By using ComposeExportedValue method). Put it simply, How can I pass various variables to the constructor without having to rebuild the whole CompositionContainer again?

So, which of these 3 approaches are better in your opinion. And how can I implement the constructor approach as mentioned? Hope I described my problem clearly.
Thanks and apologies for the lengthy question.
P.S. I'm using the MEF version which comes with .Net 4.

1
Did you want to instantiate a new ILogger for each car? Or, as @blindmeis suggests, an IEnumerable<Car> within the ILogger? I had a similar issue, see my answer to: stackoverflow.com/q/9626227/210709IAbstract
@IAbstract: Please see my comment on blindmeis's reply.Kamyar

1 Answers

0
votes

you wrote you wanna log a list of cars, so shouldnt it be:

public interface ILogger
{
   void Log(IEnumerable<Car> cars);
}