简体   繁体   English

具有 1 个泛型类型的类中具有 2 个泛型类型的方法

[英]Methods with 2 generic types in class with 1 generic type

I have the following:我有以下几点:

public class P1 {
  public P2 P2 { get; set; }
  public P4 P4 { get; set; }
}

public class P2 {
  public P3 P3 { get; set; }
}

public class P3 { }

public class P4 { }

I need a Mapper for P1 as follows:我需要 P1 的映射器,如下所示:

Mapper mapper = new Mapper<P1>();

But I would like to use it as follows:但我想按如下方式使用它:

Mapper<P1> mapper = Mapper.For<P1>()
  .Add(p1 => p1.P2).And(p2 => p2.P3)
  .Add(p1 => p1.P4);

So I have:所以我有:

public class Mapper {
  public static Mapper<T> For<T>() {
    return new Mapper<T>();
  }
}

public class Mapper<T> {

  private List<LambdaExpression> _expressions = new List<LambdaExpression>();

  public Mapper<T> Add<K>(Expression<Func<T, K>> expression) {
    // Add expression to expressions
    return this;
  }

  public Mapper<T> And<K>(Expression<Func<T, K>> expression) {
    // Add expression to expressions
    return this;
  }

}

My problem is how to deal with Child Properties.我的问题是如何处理子属性。

Note that my Mapper code only allows to do this:请注意,我的 Mapper 代码只允许这样做:

  Mapper<P1> mapper = Mapper.For<P1>()
    .Add(p1 => p1.P2).And(p1 => p1.P2.P3);

And not this:而不是这个:

  Mapper<P1> mapper = Mapper.For<P1>()
    .Add(p1 => p1.P2).And(p2 => p2.P3);

I think the methods should return Mapper but in fact I want to create a Mapper ...我认为这些方法应该返回 Mapper 但实际上我想创建一个 Mapper ...

K is only a way to define the expression when calling a method. K 只是在调用方法时定义表达式的一种方式。

Does anyone knows how to do this?有谁知道如何做到这一点?

UPDATE更新

Answer with ContinuationMapper:用 ContinuationMapper 回答:

public class Mapper<T> {

  protected List<LambdaExpression> Paths { get; set; } = new List<LambdaExpression>();

  public ContinuationMapper<T, TCont> Add<TCont>(Expression<Func<T, TCont>> path) {

    Paths.Add(path);

    return new ContinuationMapper<T, TCont>(Paths);

  }

}

public class ContinuationMapper<TBase, TCurrent> : Mapper<TBase> {

  public ContinuationMapper(List<LambdaExpression> paths) {
    Paths = paths;
  }

  public ContinuationMapper<TBase, TNext> And<TNext>(Expression<Func<TCurrent, TNext>> path) {

    base.Paths.Add(path);

    return new ContinuationMapper<TBase, TNext>(base.Paths);

  }

}

I see the following problems with your current approach:我发现您当前的方法存在以下问题:

  • It shouldn't be possible to do an And before an Add .应该不可能在Add之前执行And
  • At the end of an And (or an Add ), you have two types of type information: The base type for a new Add , and the continuation type for a new And .And (或Add )的末尾,您有两种类型的类型信息:新Add基本类型和新And延续类型 You cannot "store" that type of information at compile-time in a generic type with only one generic parameter.您不能在编译时将这种类型的信息“存储”在只有一个泛型参数的泛型类型中。

Luckily, the type system can help here, if we split your one class in two:幸运的是,类型系统可以在这里提供帮助,如果我们将您的一个类分成两部分:

public class Mapper<T>
{
    public ContinuationMapper<T, TCont> Add<TCont>(Expression<Func<T, TCont>> expression) {
        // ...
        return new ContinuationMapper<T, TCont>(...);
    }
}

public class ContinuationMapper<TBase, TCurrent> : Mapper<TBase>
{
    public ContinuationMapper<TBase, TNext> And<TNext>(Expression<Func<TCurrent, TNext>> expression) {
        // ...
        return new ContinuationMapper<TBase, TNext>(...);
    }
}

Obviously, you will have to pass the state of your expression list to the new classes, which is left as an exercise to the reader.显然,您必须将表达式列表的状态传递给新类,这留给读者作为练习。 As an added bonus, you can even make your classes immutable, if you want.作为额外的奖励,如果您愿意,您甚至可以使您的类不可变。

In essence you don't want to bind the method types to the class type so you need to use 2 new generic types.本质上,您不想将方法类型绑定到类类型,因此您需要使用 2 个新的泛型类型。 sort of like the following.有点像下面这样。

 public Mapper<T> Add<V,K>(Expression<Func<V, K>> expression) {
    // Add expression to expressions
    return this;
  }

  public Mapper<T> And<V,K>(Expression<Func<V, K>> expression) {
    // Add expression to expressions
    return this;
  }

Example:例子:

Mapper<P1> mapper = Mapper.For<P1>()
 .Add((P1 p1) => p1.P2).And((P2 p2) => p2.P3)
 .Add((P1 p1) => p1.P4);

If you want the Add to be tied to the T and the and to be tied to the last property you'll need to provide back a wrapper class like如果您希望将Add绑定到T并将 and 绑定到最后一个属性,则需要提供一个包装类,例如

Mapper<T,V>{
public Mapper<T> Add<V>(Expression<Func<T, V>> expression) {
// Add expression to expressions
return Mapper.Wrap<T,V>(this);
}

public Mapper<T> And<V>(Expression<Func<V, K>> expression) {
    // Add expression to expressions
 return this;
   }
 }

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

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