Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Collection using Generic types or Interface

I have a set of classes (MyClass1, MyClass2, MyClass3) that implement an interface (IMyClass).

I am interested in creating a method to fill and return a list (Collection.Generics.Lists<>) of objects that have common interface MyClassX (List<IMyClass>). But how?

Each class has a constructor MyClassX which does something different. So I can not create a BaseClass and use a common constructor for all.

By interface I can not do:

public List<IMyClass> Fill(string[] ItemsPassedByParam, IMyClass InstanceOfMyClassX)
    List MyList = new List<IMyClass>();
    foreach (item in ItemsPassedByParam)
    {
        MyList.Add (new IMyClass (item)); //can't do new from an Interface!!
    }
}

Also I tried using generics type, TMyClass in the next example, but neither has worked for me (though I have not very deep notions about generic types):

public List<TMyClass> Fill(string[] ItemsPassedByParam, Type TypeOfMyClassX)
    List MyList = new List <TMyClass> ();
    foreach (item in ItemsPassedByParam)
    {
        MyList.Add (new TMyClass (item)); //can't do new from a Generic Type!!
    }
}

I tried also to externalize the code inside the Constructor of MyClassX in a method, but I can't call the method since de object is not initialized (there is no new () ).

In these cases which is the solution?

Thanks in advance!

like image 333
Alex Avatar asked Mar 16 '26 23:03

Alex


2 Answers

It sounds like you want the Fill method to create a List<T> from the passed in string values where T is a derivation of IMyClass.

What you need to do is pass a factory function into the Fill method which allows for the creation of IMyClass derived instances.

public List<IMyClass> Fill(
  string[] ItemsPassedByParam, 
  Func<string,IMyClass> createFunc)

  List MyList = new List<IMyClass>();
  foreach (item in ItemsPassedByParam) {
    MyList.Add(createFunc(item));        
  }
}

Then at the place you call Fill you can choose which derivation of IMyClass to use

string[] items = ...;
List<IMyClass> list1 = Fill(items, item => new MyClass1(item));
List<IMyClass> list2 = Fill(items, item => new MyClass2(item));
like image 179
JaredPar Avatar answered Mar 18 '26 13:03

JaredPar


The best option here is to create a IMyClassFactory that handles taking the parameter, figuring out which concrete type to construct, call the constructor, and return it:

public class IMyClassFactory
{
    public static IMyClass CreateInstance(string item)
    {
        switch(item)
        {
            case "SomeValue":
            case "SomeValue2":
                return new MyClass1(item);
            case "SomeOtherValue":
                return new MyClass2(item);
        }
    }
}

That factory obviously assumes that you can infer type from the string being passed in to the factory. There's a good chance that isn't the case, in which case you need to add another parameter that allows you to infer the concrete type to instantiate.

Once you have the factory, then you can make your original method use the Factory:

public List<IMyClass> Fill(string[] ItemsPassedByParam)
{
    List MyList = new List<IMyClass>();

    foreach (item in ItemsPassedByParam)
    {
        MyList.Add(IMyClassFactory.CreateInstance(item));
    }
}
like image 37
Justin Niessner Avatar answered Mar 18 '26 12:03

Justin Niessner



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!