构造函数对类型参数的签名约束
本文关键字:约束 类型参数 构造函数 | 更新日期: 2023-09-27 17:58:55
public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source) where TV : new(TU)
{
return source.Select(x => new TV(TU));
}
问题是我不能给出新的(TU(约束。
- 这个问题有什么解决办法吗
我有两种方法:
首先使用Activator。创建实例
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 });
}
第一个方法可以工作,但感觉很脏,并且存在错误调用构造函数的风险,特别是当方法不受约束时。
因此,我认为第二种方法是更好的解决方案。
也许传入一个Func,它可以从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));
也许最简单的方法是在调用位置显式地给出从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
}