C#Lambda +扩展+流利 - 我该怎么做?

时间:2009-08-22 08:21:21

标签: c# lambda expression-trees fluent-interface

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

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

在较高的层面上,我知道我可能会有一个ITransformer,一个ITransformationRule和ITransformationResult,还有一些其他对象来实现这一目标。

在创建Transformation类时,我希望代码如何工作......

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

据我所知,我的TransformerBase需要实现采用Func或Expression的“Transform”方法,并且我理解它需要保留ITransformationRules的集合。我也理解我可能会使用Extension方法来处理“WhenCreatedBefore”和“ClassifyAs”方法。

麻烦的是,我无法弄清楚如何使一切顺利。我查看了Fluent Validation .NET的源代码,因为它以这种方式验证,但复杂性让我感到害怕。我正在寻找一个涵盖这个的教程,或者是一个以非常简单的方式拼写它的人。

提前致谢。

3 个答案:

答案 0 :(得分:2)

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

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

只需添加来自here的ForEach,并注明默认情况下未包含的原因。

如果你想使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#中。重新实现它的查询部分将是愚蠢和浪费,你想要的是添加副作用导致操作。这很好(你有可变对象所以这几乎不会导致问题)只需添加这些操作。只是让它们继续产生输入将使你的代码流畅。

答案 1 :(得分: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;  
    }
}

答案 2 :(得分:-1)

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

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