Constructor Signature Constraints for type parameters

public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source) where TV : new(TU)
{
    return source.Select(x => new TV(TU));
}

The problem is that I cannot give new restrictions (TU).

  • Is there any solution to this problem?
+3
source share
3 answers

Perhaps the easiest way is to explicitly specify the formula from TUto TVin the calling place, like here, after option 1. If you prefer to hide the conversion details behind the scenes so that it works wherever you call the extension method to avoid repeating the formula, then the interface is suitable as it can be used as a limitation for the extension method:

class Program
{
    static void Main(string[] args)
    {
        IEnumerable<U> uSequence = new List<U>();
        IEnumerable<V> vSequence1 = uSequence.To(u => new V(u)); //Option 1 : explicit transformation, needs neither any interface nor explicit types (type inference at work)
        IEnumerable<V> vSequence2 = uSequence.To<U, V>(); //Option 2 : implicit transformation internally supported from U to V by type V thanks to IBuildableFrom<TV, TU>, but you must precise To<U, V>() with the types
    }
}

public static class Extensions    {
    //Option 1
    public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source, Func<TU,TV> transform)
    {
        return source.Select(tu => transform(tu));
    }

    //Option 2
    public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source) where TV : IBuildableFrom<TV, TU>, new()
    {
        return source.Select(tu => new TV().BuildFrom(tu));
    }
}

public interface IBuildableFrom<TV, TU>
{
    TV BuildFrom(TU tu);
}

public class U { } //Cheesy concrete class playing the rôle of TU
public class V : IBuildableFrom<V, U> //Cheesy concrete class playing the rôle of TV
{
    public V BuildFrom(U u)
    {
        //Initialization of this' properties based on u ones
        return this;
    }

    public V(U u) { }//Used by option 1
    public V() { } //Used by option 2
}
+1
source

I have two approaches for you:

First, using Activator.CreateInstance

public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source)
{ 
  return source.Select(m => (TV) Activator.CreateInstance(typeof(TV), m));
}

-, , :

public interface IRequiredMember
{}

public interface IHasNeccesaryMember
{
  IRequiredMember Member
  {
    get;
    set;
  }
}

public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source)
            where TV : IHasNeccesaryMember, new()
            where TU : IRequiredMember
 {
    return source.Select(m => new TV{ Member = m });
 }

, , , , .

, - .

+4

Maybe pass to Func, which can create a TV from TU:

public static IEnumerable<TV> To<TU, TV>(
    this IEnumerable<TU> source, 
    Func<TU, TV> builder)
    where TV : class
{
    return source.Select(x => builder(x));
}

and call with

tus.To(x => new TV(x));
+3
source

All Articles