C# 类型参数上的构造函数签名约束

C# 类型参数上的构造函数签名约束,c#,generics,extension-methods,C#,Generics,Extension Methods,问题是我不能给出newTU约束 这个问题有什么解决办法吗? 可能会传入一个Func,它可以从TU创建电视: public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source) where TV : new(TU) { return source.Select(x => new TV(TU)); } 我为您提供了两种方法: 首先使用Activator.CreateInstan

问题是我不能给出newTU约束

这个问题有什么解决办法吗?
可能会传入一个Func,它可以从TU创建电视:

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

我为您提供了两种方法:

首先使用Activator.CreateInstance

tus.To(x => new TV(x));
其次,您可以使用接口来定义属性,而不是使用参数化构造函数:

public static IEnumerable<TV> To<TU, TV>(this IEnumerable<TU> source)
{ 
  return source.Select(m => (TV) Activator.CreateInstance(typeof(TV), m));
}
第一个方法可以工作,但感觉脏,并且有可能使构造函数调用出错,特别是当该方法不受约束时


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

也许最简单的方法是在呼叫地点明确给出从TU到TV的公式,如下面的选项1。如果希望将变换的细节隐藏在场景后面,使其在调用扩展方法的任何位置工作,以避免重复公式,则接口是合适的,因为它可以用作扩展方法的约束:

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 });
 }

您只能指定默认构造函数,C中不允许使用带参数的构造函数。@Srinivas是的,我注意到了。但有什么原因可以解决这个问题吗?+1与我的想法完全不同,但方法非常有趣。@Amir是的,我自己也不确定,一方面,它将如何创建TV对象的知识从扩展方法转移到调用方,但另一方面,它在创建TV对象的方式上更加灵活。@Graham Clark:您的实现可以缩短,以返回source.Selectbuilder。这与使用Enumerable有何不同。直接选择tus.Selectx=>newTVX@康斯坦丁一世也注意到了这个问题。然后我们回到了起点。这是一个内置的转换器类。@Konstantin有了这个,你不需要使用新的TVx,你可以使用任何可以创建电视的东西。这取决于你想做什么。我认为@Xhalent的解决方案可能更适用于这个特定的问题。我如何才能将成员更改为TV的构造函数?@Amir:您不能使用接口定义构造函数-例如,请参阅ISerializable,因此我认为成员规范与您将要得到的最接近。
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 });
 }
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
}