4

我希望能够创建采用给定对象的“转换”类,对其执行一系列转换(即更改属性值)并跟踪执行的转换。执行的转换将根据所提供对象的属性而有所不同。

我希望能够使用流畅的样式界面在给定的转换类中应用转换规则(它们是有限的和通用的)。

在高层次上,我知道我可能会有一个 ITransformer、一个 ITransformationRule 和 ITransformationResult 以及一些其他对象来实现这一点。

创建转换类时我希望代码如何工作......

public OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
   public OfflinePersonToOnlineTransformation()
   {
        Transform(x => x.PersonClassification)
           .WhenCreatedBefore("1/1/2000")
           .ClassifyAs("Online");
   }
}

我知道我的 TransformerBase 需要实现采用 Func 或 Expression 的“Transform”方法,并且我知道它需要保留 ITransformationRules 的集合。我也明白我可能会为“WhenCreatedBefore”和“ClassifyAs”方法使用扩展方法。

问题是,我不知道如何让它全部工作。我已经查看了 Fluent Validation .NET 的源代码,因为它以这种方式进行验证,但复杂性让我感到沮丧。我正在寻找涵盖此内容的教程,或者以非常简单的方式将其拼写出来的人。

提前致谢。

4

3 回答 3

2

当 linq 为您完成大部分工作时,不太清楚为什么要进行所有这些工作:

IEnumerable<Person> somePeople; // from wherever
somePeople.Where(x => x.CreateDate < new DateTime(2000,1,1))
   .ForEach(x =>  x.PersonClassification = "Online");

只需从此处添加 ForEach,并注意为什么默认情况下不包含它的 proisos。

如果你想让 WhereCreatedBefore 更好,那么像这样一个简单的扩展:

static class PersonExtensions
{
    public static bool WhereCreatedBefore(this Person p,
        int year, int month, int day)
    {
         return p.CreateDate < new DateTime(year,month,day);
    }
}

这本身很有用,并为您提供:

somePeople.Where(x => x.CreatedBefore(2000,1,1))
   .ForEach(x =>  x.PersonClassification = "Online");

当简单地扩展 linq 为您提供的工具时,为什么要限制自己使事情变得更容易。

如果您想链接多个副作用,只需对 ForEach 进行简单的更改,如下所示:

public static IEnumerable<T> Modify<T>(
    this IEnumerable<T> input, Action<T> action)
{
    foreach (var x in input)
    {
        action(x);
        yield return x;
    }
}

给你:

somePeople.Where(x => x.CreatedBefore(2000,1,1))
   .Modify(x =>  x.PersonClassification = "Online");
   .Modify(x =>  x.LastModifiedBy = Environment.UserName);

或者,如果您使用它的语言集成部分:

(from p in somePeople where p.CreatedBefore(2000,1,1)) select p)
   .Modify(p =>  p.PersonClassification = "Online");
   .Modify(p =>  p.LastModifiedBy = Environment.UserName);

如果您真的*想要您可以编写一个 ClassifyAs 扩展,如下所示:

public static IEnumerable<Person> ClassifyAs(
    this IEnumerable<Person> input, string classification)
{
    foreach (var p in input)
    {
        p. PersonClassification = classification;
        yield return p;
    }
}

给你你的原件:

(from p in input where p.CreatedBefore(2000,1,1)) select p).ClassifyAs("Online");

这是一个班轮!不需要花哨的框架或类型层次结构,只需要一些有用的扩展方法。Linq 通常设计良好、实现良好、无处不在并且很好地集成到 c# 中。重新实现它的查询部分将是愚蠢和浪费的,你想要的是向它添加导致操作的副作用。这很好(你有可变对象,所以这几乎不会引起问题)只需添加这些操作。只是让他们继续产生他们的输入将使您的代码风格流利。

于 2009-08-23T18:55:51.790 回答
0

我有一个想法;它唯一的伪代码,但这有帮助吗?

public interface IPerson {
  string PersonClassification { get; set; }
  DateTime CreateDate { get; set; }
 }

public class Person :  IPerson {
  public string PersonClassification { get; set; }
  public DateTime CreateDate { get; set; }
 }




public class TransformerBase<T> 
 where T : IPerson {

    T Person { get; set; }

    T Transform(Func<T, PersonClassification> transformer) {
        return transformer(person);
    }
}


public class  OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
   public OfflinePersonToOnlineTransformation()
   {
        Transform(x => x.PersonClassification)
           .WhenCreatedBefore("1/1/2000")
           .ClassifyAs("Online");
   }
}

public static class Extensions {

    public static T WhenCreatedBefore<T>(this T person, string date) where T : IPerson{
        if(person == null || person.CreateDate > DateTime.Parse(date)) 
            return null
        return person;  
    }
    public static T Classify<T>(this T person, string classification)where T : IPerson{
        if(person != null) 
            person.PersonClassification = classification;
        return person;  
    }
}
于 2009-08-22T09:45:56.523 回答
-1

退后一步,先编写一个简单流畅的界面可能会有所帮助。您不需要泛型或多个类来实现一个。流畅的界面模式的主要好处是易于阅读代码。它是通过从方法中返回 this 以促进方法链接来完成的。这是一个基本的例子。我将从这里开始并向后工作以达到您想要的结果。

    public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }
    class Calculator
    {
        List<int> values = new List<int>();

        public Calculator Add(int value)
        {
            values.Add(value);
            return this;
        }

        public int Count()
        {
            return values.Count;                
        }

        public int Sum()
        {
            return values.Sum();
        }

    }
    private void Form1_Load(object sender, EventArgs e)
    {
        //returns 3
        int sum =
            new Calculator()
            .Add(1)
            .Add(2)
            .Sum();
    }
}
于 2009-08-22T18:00:40.920 回答