类型参数构造函数签名约束
public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source) where TV : new(TU)
{
return source.Select(x => new TV(TU));
}
问题是我不能给出新的(TU)约束。类型参数构造函数签名约束
- 有没有解决这个问题的方法?
也许最简单的方法是在调用的地方明确地将公式从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));
+1与我的想法完全不同,但非常有趣。 – 2011-06-10 08:17:10
@Amir是的,我自己也不太确定,一方面它提供了如何从扩展方法创建电视对象到调用者的知识,另一方面它在电视对象的方式上更加灵活创建。 – 2011-06-10 08:19:42
@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 });
}
第一种方法的作品,但感觉很脏,有越来越构造函数调用错误的风险,尤其是在方法不受限制。
因此,我认为第二种方法是一个更好的解决方案。
第二种方法看起来非常好! – 2011-06-10 08:30:33
如何将会员更改为电视的构造函数? – 2011-06-10 08:32:16
@Amir:你不能使用接口来定义构造函数 - 例如参见ISerializable,所以成员规范尽可能接近我的想法。 – Xhalent 2011-06-10 09:05:22
你只能指定默认的构造函数,带参数的构造函数在C#中是不允许的。 – 2011-06-10 08:09:22
@Srinivas是的,我注意到了。但是有没有什么解决这个问题的原因? – 2011-06-10 08:11:02