繁体   English   中英

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

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

我有以下几点:

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 { }

我需要 P1 的映射器,如下所示:

Mapper mapper = new Mapper<P1>();

但我想按如下方式使用它:

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

所以我有:

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

}

我的问题是如何处理子属性。

请注意,我的 Mapper 代码只允许这样做:

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

而不是这个:

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

我认为这些方法应该返回 Mapper 但实际上我想创建一个 Mapper ...

K 只是在调用方法时定义表达式的一种方式。

有谁知道如何做到这一点?

更新

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

  }

}

我发现您当前的方法存在以下问题:

  • 应该不可能在Add之前执行And
  • And (或Add )的末尾,您有两种类型的类型信息:新Add基本类型和新And延续类型 您不能在编译时将这种类型的信息“存储”在只有一个泛型参数的泛型类型中。

幸运的是,类型系统可以在这里提供帮助,如果我们将您的一个类分成两部分:

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

显然,您必须将表达式列表的状态传递给新类,这留给读者作为练习。 作为额外的奖励,如果您愿意,您甚至可以使您的类不可变。

本质上,您不想将方法类型绑定到类类型,因此您需要使用 2 个新的泛型类型。 有点像下面这样。

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

例子:

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

如果您希望将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