简体   繁体   English

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

[英]Constructor Signature Constraints on 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 can't give the new(TU) constraints.问题是我不能给出新的(TU)约束。

  • Is there any solution to this problem?这个问题有什么解决办法吗?

I've got two approaches for you:我为您提供了两种方法:

Firstly using Activator.CreateInstance首先使用 Activator.CreateInstance

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

Secondly, you could use interfaces to define properties rather than use parameterized constructors:其次,您可以使用接口来定义属性,而不是使用参数化构造函数:

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

The first method works but feels dirty and there is the risk of getting the constructor call wrong, particularly as the method is not constrained.第一种方法可行,但感觉很脏,并且存在构造函数调用错误的风险,特别是在该方法不受约束的情况下。

Therefore, I think the second method is a better solution.因此,我认为第二种方法是更好的解决方案。

Maybe pass in a Func which can create a TV from a TU:也许传入一个可以从 TU 创建电视的 Func:

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

Maybe the easiest way is to explicitly give the formula from TU to TV at the calling place like option 1 here after.也许最简单的方法是在呼叫地点明确地将公式从TU提供给TV ,就像后面的选项 1 一样。 If you prefer to hide the details of the transformation behind the scene to have it work anywhere where you call the extension method to avoid repeating the formula, then an interface is appropriate since it can be used as a constraint for an 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's ones
        return this;
    }

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM