类型参数构造函数签名约束

问题描述:

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

问题是我不能给出新的(TU)约束。类型参数构造函数签名约束

  • 有没有解决这个问题的方法?
+0

你只能指定默认的构造函数,带参数的构造函数在C#中是不允许的。 – 2011-06-10 08:09:22

+0

@Srinivas是的,我注意到了。但是有没有什么解决这个问题的原因? – 2011-06-10 08:11:02

也许最简单的方法是在调用的地方明确地将公式从TU改为TV,就像后面的选项1一样。如果您希望隐藏场景背后的转换细节,以使其在您调用扩展方法的任何位置工作以避免重复公式,那么接口是适当的,因为它可以用作扩展方法的约束:

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's ones 
     return this; 
    } 

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

也许传递函数求能够从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)); 
} 

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

+1与我的想法完全不同,但非常有趣。 – 2011-06-10 08:17:10

+0

@Amir是的,我自己也不太确定,一方面它提供了如何从扩展方法创建电视对象到调用者的知识,另一方面它在电视对象的方式上更加灵活创建。 – 2011-06-10 08:19:42

+0

@Graham Clark:你的实现可以缩短为“return source.Select(builder)”。这与使用Enumerable.Select直接“tus.Select(x => new TV(x))”有什么不同? – 2011-06-10 08:39:30

我要告诉你两种方法调用:

首先使用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 }); 
} 

第一种方法的作品,但感觉很脏,有越来越构造函数调用错误的风险,尤其是在方法不受限制。

因此,我认为第二种方法是一个更好的解决方案。

+0

第二种方法看起来非常好! – 2011-06-10 08:30:33

+0

如何将会员更改为电视的构造函数? – 2011-06-10 08:32:16

+0

@Amir:你不能使用接口来定义构造函数 - 例如参见ISerializable,所以成员规范尽可能接近我的想法。 – Xhalent 2011-06-10 09:05:22