views:

1910

answers:

5

I have a set of some classes which are all capable of being constructored with an argument being an instance of a particular interface. Since they all can be constructed by this same object (and the process during which this construction happens is largely the same in all cases), I figured perhaps templating would work. Basically, I want to do something like this:

public static void dostuff<T, U> (List<T> items)
{
    foreach (T item in items)
    {
        func(new U(item).SpecialMember);
    }
}

Of course, that won't compile since U is templated and thus lacks SpecialMember as well as the T constructor.

Basically, any given implementation of the inteface T has certain features. U is an implementation of T which has an additional feature that is needed *and* which can be constructed from an any instance of U`.

Advice?

A: 

You want a Factory pattern. Add a factory method to your T interface that returns U types.

Joel Coehoorn
A: 

You can add constraints to the generic parameters which will allow you to access SpecialMember for example:

public class SpecialObjFactory<T,U> where T : ISpecialMethod
where u : new()
{
}
JoshBerke
A: 

You cannot use generics to create an object like this. You can constraint the generic types like so:

public static void dostuff<T, U> (List<T> items) where T : SomeClass where U : SomethingElse
{
}

But this will only let you access members of those classes/interfaces, not constructors.

To expand on Joel's answer, you should add a method to the T interface (in my example, SomeClass) that takes a T object and returns a new U object. Something like the following:

public class SomeClass    
{
    CreateInstanceOfSomethingElse() { return new SomethingElse(this); }
}

public static void dostuff<T, U> (List<T> items) where T : SomeClass, U : SomethingElse
{
    foreach (T item in items)
    {
        func(item.CreateInstanceOfSomethingElse().SpecialMember);
    }

}

As another completely different approach, you could specify that the doStuff method takes a Func<T, U> as well, which is supposed to create a U from a T object.

public static void dostuff<T, U> (List<T> items, Func<T, U> createU)
{
    foreach (T item in items)
    {
        func(createU(item).SpecialMember);
    }

}

This gets messy if your object creation is anything more complex than a simple lamba like

t => new U(t)

Jamie Penney
+2  A: 

Unfortunately while constraints will get you some of the way there, there's no way to specify that a type has a constructor which takes certain argument: the only constructor you can require is a parameterless one.

Personally I'd like to see that change using an idea of "static interfaces" (only usable for type constraints) but for the moment the best you'll get is a type factory or reflection - or possibly a parameterless constructor and an "Init" method in the interface. None of these are nice options, frankly.

Jon Skeet
A: 
public static void dostuff<T, U> (List<T> items)
{
    foreach (T item in items)
    {
        U obj = ( U )System.Activator.CreateInstance( typeof( U ), item );
        func(obj.SpecialMember);
    }
}
Jakub Filak