首页 > 其他分享 >链式-父类中返回子类对象

链式-父类中返回子类对象

时间:2023-05-18 18:34:14浏览次数:48  
标签:memberExpression return 子类 expression 链式 父类 Expression public Select

一晃五年没写博客了,依旧再C#上耕耘,依旧没有啥建树,现在也不知道.net上还有多少人再使用,在这里分享一些自己觉得写的还算优雅的代码。

对于自己写着完的代码,我特别喜欢链式(来源于jQuery的影响吧),大部分时候链式就是将返回值为void类型的对象,返回this指针,直到我遇到一个特殊情况——在父类中返回子类类型。大部分情况父类都不知道子类有什么,根本没有返回子类的需求

但是由于链式调用父类的接口返回父类对象,就无法继续链式了。说明可能不清楚,直接show code



 1  public class OldWhereV2<T>
 2     {
 3         protected Expression<Func<T, bool>> expression = null;
 4 
 5         public OldWhereV2<T> Where(Expression<Func<T, bool>> memberExpression)
 6         {
 7             return this;
 8         }
 9 
10         public OldWhereV2<T> Or(Expression<Func<T, bool>> memberExpression)
11         {
12             return this;
13         }
14 
15         public OldWhereV2<T> Add(Expression<Func<T, bool>> memberExpression)
16         {
17             return this;
18         }
19     }
20 
21     public class OldQeuryV2<T> : OldWhereV2<T>
22     {
23 
24         public OldQeuryV2<T> Select(Expression<Func<T, object>> memberExpression)
25         {
26             return this;
27         }
28 
29         public OldQeuryV2<T> Take(int count)
30         {
31             return this;
32         }
33 
34         public OldQeuryV2<T> Order(Expression<Func<T, object>> memberExpression, bool asc)
35         {
36             return this;
37         }
38     }

调用的时候,如果使用链式



1  var query =new OldQeuryV2<Train>()
2                .Select(x => x.Apply_Time)
3                .Select(x => x.Apply_Time)
4                .Select(x => x.Approval_OrgName)
5                .Where(x => x.Create_Time > DateTime.Now)
6                .Add(x => x.Approval_OrgName == "")
7                .Order(x => x.Approval_OrgGID, true)
8                .Order(x => x.Apply_Time, false)
9                .Take(10);

 .Order(x => x.Approval_OrgGID, true) 这行代码会报错的。因为Where返回的是OldWhereV2<T>类型,而Order方法要求OldQeuryV2<T>类型

 这个问题困扰我一晚,后来我记得在哪里看过一本书,书中有泛型自包含的例子,但是当时完全看不懂,但是此处感觉使用完全没毛病所以就做了简单修改

 1  public abstract class Condition<T, M> where M : Condition<T, M>
 2     {
 3         protected Expression<Func<T, bool>> expression = null;
 4 
 5         public M Where(Expression<Func<T, bool>> memberExpression)
 6         {
 7             expression = memberExpression;
 8             return (M)this;
 9         }
10 
11         public M Or(Expression<Func<T, bool>> memberExpression)
12         {
13             if (expression == null)
14             {
15                 expression = memberExpression;
16             }
17             else
18             {
19                 var invokedExpr = Expression.Invoke(memberExpression, expression.Parameters.Cast<Expression>());
20                 expression = Expression.Lambda<Func<T, bool>>(Expression.OrElse(expression.Body, invokedExpr), expression.Parameters);
21             }
22             return (M)this;
23         }
24 
25         public M Add(Expression<Func<T, bool>> memberExpression)
26         {
27             if (expression == null)
28             {
29                 expression = memberExpression;
30             }
31             else
32             {
33                 var invokedExpr = Expression.Invoke(memberExpression, expression.Parameters.Cast<Expression>());
34                 expression = Expression.Lambda<Func<T, bool>>(Expression.AndAlso(expression.Body, invokedExpr), expression.Parameters);
35             }
36             return (M)this;
37         }
38     }
39 
40     public class Qeury<T> : Condition<T, Qeury<T>>
41     {
42         List<MemberInfo> selects = new List<MemberInfo>();
43         Dictionary<MemberInfo, bool> orders = new Dictionary<MemberInfo, bool>();
44         int count = 1000;
45 
46         public Qeury<T> Select(Expression<Func<T, object>> memberExpression)
47         {
48             MemberInfo memberInfo = memberExpression.GetMemberInfo();
49             if (!selects.Contains(memberInfo))
50             {
51                 selects.Add(memberInfo);
52             }
53             return this;
54         }
55 
56         public Qeury<T> Take(int count)
57         {
58             this.count = count;
59             return this;
60         }
61 
62         public Qeury<T> Order(Expression<Func<T, object>> memberExpression, bool asc)
63         {
64             MemberInfo memberInfo = memberExpression.GetMemberInfo();
65             if (orders.ContainsKey(memberInfo))
66             {
67                 orders[memberInfo] = asc;
68             }
69             else
70             {
71                 orders.Add(memberInfo, asc);
72             }
73             return this;
74         }
75 
76         public string QeurySql()
77         {
78             var queryInfo = new QueryInfo()
79             {
80                 WhereExpression = this.expression,
81                 SelectFields = this.selects,
82                 Orders = this.orders,
83                 Count = this.count
84             };
85 
86             return TableAnalysis.GetTableInfo(typeof(T)).QeurySql(queryInfo);
87         }
88     }

这里将Condition<T>类修改为Condition<T,M> 而M是Condition<T,M>的子类,返回的时候只需要返回M类型就好了,当然由于Condition返回了子类,所以我把它设置成了抽象类,但是也可以不用。由于Qeury<T> :实现了Condition<T, Qeury<T>>,所以子类就可以正常调用父类的方法了。

具体例子如下:

1 var query =new Qeury<Train>()
2                .Select(x => x.Apply_Time)
3                .Select(x => x.Apply_Time)
4                .Select(x => x.Approval_OrgName)
5                .Where(x => x.Create_Time > DateTime.Now)
6                .Add(x => x.Approval_OrgName == "")
7                .Order(x => x.Approval_OrgGID, true)
8                .Order(x => x.Apply_Time, false)
9                .Take(10);

这个算是奇技淫巧,发出来给大家看看,不过不链式不久没有烦恼了吗,正常如下面定义就好了

 1     public class OldCondition<T>
 2     {
 3         public void Where(Expression<Func<T, bool>> memberExpression)
 4         {
 5 
 6         }
 7 
 8         public void Or(Expression<Func<T, bool>> memberExpression)
 9         {
10 
11         }
12 
13         public void Add(Expression<Func<T, bool>> memberExpression)
14         {
15 
16         }
17     }
18 
19     public class OldQeury<T> : OldCondition<T>
20     {
21         public void Select(Expression<Func<T, object>> memberExpression)
22         {
23 
24         }
25 
26         public void Take(int count)
27         {
28 
29         }
30 
31         public void Order(Expression<Func<T, object>> memberExpression, bool asc)
32         {
33 
34         }
35     }
View Code

 

标签:memberExpression,return,子类,expression,链式,父类,Expression,public,Select
From: https://www.cnblogs.com/watermoon2/p/17412967.html

相关文章

  • 子类和父类的相互转换
    父类:publicclassfather{ publicvoidsay() { System.out.println("爸爸在说话....."); }} 子类:publicclasssonextendsfather{publicvoidsay(){System.out.println("儿子在说话.....");}} 测试:publicclassmain{/***......
  • 为什么被final修饰的方法不能被子类重写(无法被覆盖)
       方法覆盖是子类重写父类的方法实现。如果一个方法被final修饰,那么子类是无法重写该方法。注意final关键字只是让方法无法被覆盖,但不影响方法的继承。子类依旧可以继承父类的final方法,只是不能对其实现进行修改。好处就是:防止子类不经意间修改父类方法的实现,破坏了程序的正......
  • CAS 和 原子类
    什么是CAS全称是Compare-And-Swap,对数据进行原子性操作,sun.misc.Unsafe类的各个native方法实现的比较当前工作内存中的值和主内存中的值,如果相同则执行规定操作,否则什么都不做或者重来一次,重来就是自旋锁了java各种锁看这里CASVSvolatileVSsynchronizedCAS:保证......
  • 父类析构函数一定要使用析构函数的原因
    如果基类的析构函数不是虚函数,在删除一个指向派生类对象的基类指针时,只有基类的析构函数被调用,而派生类的析构函数不会被调用。这可能导致资源泄漏,未正确释放派生类分配的内存等问题。当基类的析构函数被声明为虚函数时,C++运行时会根据实际的对象类型调用相应的析构函数。这意味......
  • 多态性与鸭子类型
    多态与多态性多态指的是一类事物有多种形态,比如动物有多种形态:猫、狗、猪classAnimal:#同一类事物:动物deftalk(self):passclassCat(Animal):#动物的形态之一:猫deftalk(self):print('喵喵喵')classDog(Animal):#动物的形态之二:狗d......
  • 1163 Dijkstra Sequence + 层序遍历 + 链式前向星
    PAT题目链接:https://pintia.cn/problem-sets/994805342720868352/exam/problems/1478635670373253120这题踩了太多坑,本来没什么内容,硬是断断续续查了三天的bug:第一天:循环的时候内部判断逻辑不要写在for循环里,否则本该continue的逻辑,硬生生变成了break。我真是脑袋瓜秀逗了才会......
  • 使用 grom 后所有操作数据库的代码都使用同一个表-链式调用
    在写业务代码的时候一位同事写代码是这样的func(p*PromptRepo)GetArtPrompt(ctxcontext.Context,options...func(option*gorm.DB))(articles[]*model.ArticlePrompt,errerror){ p.db=p.db.Table(model.ArticlePrompt{}.TableName()) for_,option:=rangeop......
  • 不同的编程语言中使用管道pipe(或者说链式调用)
    目录终端语言(如bash,zsh)一般有管道符|pythonjavascriptrubymathematicac#c++scala3终端语言(如bash,zsh)一般有管道符|#将`echo`命令的输出传递给`grep`命令echo"Hello,World!"|grep"World"#将`ls`命令的输出传递给`wc`命令,以统计文件和目录的数量ls|wc......
  • Vue2中 ?. 可选链式调用操作符
    可选链运算符(?.)允许读取位于连接对象链深处的属性的值,而不必明确验证链中的每个引用是否有效。?. 运算符的功能类似于 . 链式运算符,不同之处在于,在引用为空(nullish )(null 或者 undefined)的情况下不会引起错误,该表达式短路返回值是 undefined。与函数调用一起使用......
  • C#反射获子类所继承的父类中,属性的私有get/set方法
    这两天遇到个好玩的东西,过程是这样的:有这样的两个类,它们都被封装到同一个dll中。publicabstractclassMyClass{publicintMyProperty{get;privateset;}}publicclassMyChildClass:MyClass{publicintMyProperty2{......