主頁 > .NET開發 > 動態構造任意復雜的 Linq Where 運算式

動態構造任意復雜的 Linq Where 運算式

2020-09-17 10:22:29 .NET開發

前言

       Linq 是 C# 中一個非常好用的集合處理庫,用好了能幫我們簡化大量又臭又長的嵌套回圈,使處理邏輯清晰可見,EF 查詢主要也是依賴 Linq,但是 Linq 相對 sql 也存在一些缺點,最主要的就是動態構造查詢的難度,sql 只需要簡單進行字串拼接,操作難度很低(當然出錯也相當容易),而 Linq 運算式由于對強型別運算式樹的依賴,動態構造查詢運算式基本相當于手寫 AST(抽象語法樹),可以說難度暴增,

       AST 已經進入編譯原理的領域,對計算機系統的了解程度需求比一般 crud 寫業務代碼高了幾個量級,也導致很多人覺得 EF 不好用,為了寫個動態查詢要學編譯原理這個代價還是挺高的,后來也有一些類似 DynamicLinq 的類別庫能用運算式字串寫動態查詢,

       本著學習精神,研究了一段時間,寫了一個在我的想象力范圍內,可以動態構造任意復雜的 Where 運算式的輔助類,這個輔助類的過濾條件使用了 JqGrid 的高級查詢的資料結構,這是我第一個知道能生成復雜嵌套查詢,并且查詢資料使用 json 方便決議的 js 表格插件,可以無縫根據 JqGrid 的高級查詢生成 Where 運算式,

正文

實作

       JqGrid 高級查詢資料結構定義,用來反序列化:

 1     public class JqGridParameter
 2     {
 3         /// <summary>
 4         /// 是否搜索,本來應該是bool,true
 5         /// </summary>
 6         public string _search { get; set; }
 7         /// <summary>
 8         /// 請求發送次數,方便服務器處理重復請求
 9         /// </summary>
10         public long Nd { get; set; }
11         /// <summary>
12         /// 當頁資料條數
13         /// </summary>
14         public int Rows { get; set; }
15         /// <summary>
16         /// 頁碼
17         /// </summary>
18         public int Page { get; set; }
19         /// <summary>
20         /// 排序列,多列排序時為排序列名+空格+排序方式,多個列之間用逗號隔開,例:id asc,name desc
21         /// </summary>
22         public string Sidx { get; set; }
23         /// <summary>
24         /// 分離后的排序列
25         /// </summary>
26         public string[][] SIdx => Sidx.Split(", ").Select(s => s.Split(" ")).ToArray();
27         /// <summary>
28         /// 排序方式:asc、desc
29         /// </summary>
30         public string Sord { get; set; }
31         /// <summary>
32         /// 高級搜索條件json
33         /// </summary>
34         public string Filters { get; set; }
35 
36         /// <summary>
37         /// 序列化的高級搜索物件
38         /// </summary>
39         public JqGridSearchRuleGroup FilterObject => Filters.IsNullOrWhiteSpace()
40             ? new JqGridSearchRuleGroup { Rules = new[] { new JqGridSearchRule { Op = SearchOper, Data = https://www.cnblogs.com/coredx/p/SearchString, Field = SearchField } } }
41             : JsonSerializer.Deserialize<JqGridSearchRuleGroup>(Filters ?? string.Empty);
42 
43         /// <summary>
44         /// 簡單搜索欄位
45         /// </summary>
46         public string SearchField { get; set; }
47         /// <summary>
48         /// 簡單搜索關鍵字
49         /// </summary>
50         public string SearchString { get; set; }
51         /// <summary>
52         /// 簡單搜索操作
53         /// </summary>
54         public string SearchOper { get; set; }
55 
56     }
57 
58     /// <summary>
59     /// 高級搜索條件組
60     /// </summary>
61     public class JqGridSearchRuleGroup
62     {
63         /// <summary>
64         /// 條件組合方式:and、or
65         /// </summary>
66         public string GroupOp { get; set; }
67         /// <summary>
68         /// 搜索條件集合
69         /// </summary>
70         public JqGridSearchRule[] Rules { get; set; }
71         /// <summary>
72         /// 搜索條件組集合
73         /// </summary>
74         public JqGridSearchRuleGroup[] Groups { get; set; }
75     }
76 
77     /// <summary>
78     /// 高級搜索條件
79     /// </summary>
80     public class JqGridSearchRule
81     {
82         /// <summary>
83         /// 搜索欄位
84         /// </summary>
85         public string Field { get; set; }
86         /// <summary>
87         /// 搜索欄位的大駝峰命名
88         /// </summary>
89         public string PascalField => Field?.Length > 0 ? Field.Substring(0, 1).ToUpper() + Field.Substring(1) : Field;
90         /// <summary>
91         /// 搜索操作
92         /// </summary>
93         public string Op { get; set; }
94         /// <summary>
95         /// 搜索關鍵字
96         /// </summary>
97         public string Data { get; set; }
98     }

       Where 條件生成器,代碼有點多,有點復雜,不過注釋也很多,稍微耐心點應該不難看懂:

  1     /// <summary>
  2     /// JqGrid搜索運算式擴展
  3     /// </summary>
  4     public static class JqGridSearchExtensions
  5     {
  6         //前端的(不)屬于條件搜索需要傳遞一個json陣列的字串作為引數
  7         //為了避免在搜索字串的時候分隔符是搜索內容的一部分導致搜索關鍵字出錯
  8         //無論定義什么分隔符都不能完全避免這種尷尬的情況,所以使用標準的json以絕后患
  9         /// <summary>
 10         /// 根據搜索條件構造where運算式,支持JqGrid高級搜索
 11         /// </summary>
 12         /// <typeparam name="T">搜索的物件型別</typeparam>
 13         /// <param name="ruleGroup">JqGrid搜索條件組</param>
 14         /// <param name="propertyMap">屬性映射,把搜索規則的名稱映射到屬性名稱,如果屬性是復雜型別,使用點號可以繼續訪問內部屬性</param>
 15         /// <returns>where運算式</returns>
 16         public static Expression<Func<T, bool>> BuildWhere<T>(JqGridSearchRuleGroup ruleGroup, IDictionary<string, string> propertyMap)
 17         {
 18             ParameterExpression parameter = Expression.Parameter(typeof(T), "searchObject");
 19 
 20             return Expression.Lambda<Func<T, bool>>(BuildGroupExpression<T>(ruleGroup, parameter, propertyMap), parameter);
 21         }
 22 
 23         /// <summary>
 24         /// 構造搜索條件組的運算式(一個組中可能包含若干子條件組)
 25         /// </summary>
 26         /// <typeparam name="T">搜索的物件型別</typeparam>
 27         /// <param name="group">條件組</param>
 28         /// <param name="parameter">引數運算式</param>
 29         /// <param name="propertyMap">屬性映射</param>
 30         /// <returns>回傳bool的條件組的運算式</returns>
 31         private static Expression BuildGroupExpression<T>(JqGridSearchRuleGroup group, ParameterExpression parameter, IDictionary<string, string> propertyMap)
 32         {
 33             List<Expression> expressions = new List<Expression>();
 34             foreach (var rule in group.Rules ?? new JqGridSearchRule[0])
 35             {
 36                 expressions.Add(BuildRuleExpression<T>(rule, parameter, propertyMap));
 37             }
 38 
 39             foreach (var subGroup in group.Groups ?? new JqGridSearchRuleGroup[0])
 40             {
 41                 expressions.Add(BuildGroupExpression<T>(subGroup, parameter, propertyMap));
 42             }
 43 
 44             if (expressions.Count == 0)
 45             {
 46                 throw new InvalidOperationException("構造where子句例外,生成了0個比較條件運算式,");
 47             }
 48 
 49             if (expressions.Count == 1)
 50             {
 51                 return expressions[0];
 52             }
 53 
 54             var expression = expressions[0];
 55             switch (group.GroupOp)
 56             {
 57                 case "AND":
 58                     foreach (var exp in expressions.Skip(1))
 59                     {
 60                         expression = Expression.AndAlso(expression, exp);
 61                     }
 62                     break;
 63                 case "OR":
 64                     foreach (var exp in expressions.Skip(1))
 65                     {
 66                         expression = Expression.OrElse(expression, exp);
 67                     }
 68                     break;
 69                 default:
 70                     throw new InvalidOperationException($"不支持創建{group.GroupOp}型別的邏輯運算運算式");
 71             }
 72 
 73             return expression;
 74         }
 75 
 76         private static readonly string[] SpecialRuleOps = {"in", "ni", "nu", "nn"};
 77 
 78         /// <summary>
 79         /// 構造條件運算式
 80         /// </summary>
 81         /// <typeparam name="T">搜索的物件型別</typeparam>
 82         /// <param name="rule">條件</param>
 83         /// <param name="parameter">引數</param>
 84         /// <param name="propertyMap">屬性映射</param>
 85         /// <returns>回傳bool的條件運算式</returns>
 86         private static Expression BuildRuleExpression<T>(JqGridSearchRule rule, ParameterExpression parameter,
 87             IDictionary<string, string> propertyMap)
 88         {
 89             Expression l;
 90 
 91             string[] names = null;
 92             //如果物體屬性名稱和前端名稱不一致,或者屬性是一個自定義型別,需要繼續訪問其內部屬性,使用點號分隔
 93             if (propertyMap?.ContainsKey(rule.Field) == true)
 94             {
 95                 names = propertyMap[rule.Field].Split('.', StringSplitOptions.RemoveEmptyEntries);
 96                 l = Expression.Property(parameter, names[0]);
 97                 foreach (var name in names.Skip(1))
 98                 {
 99                     l = Expression.Property(l, name);
100                 }
101             }
102             else
103             {
104                 l = Expression.Property(parameter, rule.PascalField);
105             }
106 
107             Expression r = null; //值運算式
108             Expression e; //回傳bool的各種比較運算式
109 
110             //屬于和不屬于比較是多值比較,需要呼叫Contains方法,而不是呼叫比較運算子
111             //為空和不為空的右值為常量null,不需要構造
112             var specialRuleOps = SpecialRuleOps;
113 
114             var isNullable = false;
115             var pt = typeof(T);
116             if(names != null)
117             {
118                 foreach(var name in names)
119                 {
120                     pt = pt.GetProperty(name).PropertyType;
121                 }
122             }
123             else
124             {
125                 pt = pt.GetProperty(rule.PascalField).PropertyType;
126             }
127 
128             //如果屬性型別是可空值型別,取出內部型別
129             if (pt.IsDerivedFrom(typeof(Nullable<>)))
130             {
131                 isNullable = true;
132                 pt = pt.GenericTypeArguments[0];
133             }
134 
135             //根據屬性型別創建要比較的常量值運算式(也就是r)
136             if (!specialRuleOps.Contains(rule.Op))
137             {
138                 switch (pt)
139                 {
140                     case Type ct when ct == typeof(bool):
141                         r = BuildConstantExpression(rule, bool.Parse);
142                         break;
143 
144                     #region 文字
145 
146                     case Type ct when ct == typeof(char):
147                         r = BuildConstantExpression(rule, str => str[0]);
148                         break;
149                     case Type ct when ct == typeof(string):
150                         r = BuildConstantExpression(rule, str => str);
151                         break;
152 
153                     #endregion
154 
155                     #region 有符號整數
156 
157                     case Type ct when ct == typeof(sbyte):
158                         r = BuildConstantExpression(rule, sbyte.Parse);
159                         break;
160                     case Type ct when ct == typeof(short):
161                         r = BuildConstantExpression(rule, short.Parse);
162                         break;
163                     case Type ct when ct == typeof(int):
164                         r = BuildConstantExpression(rule, int.Parse);
165                         break;
166                     case Type ct when ct == typeof(long):
167                         r = BuildConstantExpression(rule, long.Parse);
168                         break;
169 
170                     #endregion
171 
172                     #region 無符號整數
173 
174                     case Type ct when ct == typeof(byte):
175                         r = BuildConstantExpression(rule, byte.Parse);
176                         break;
177                     case Type ct when ct == typeof(ushort):
178                         r = BuildConstantExpression(rule, ushort.Parse);
179                         break;
180                     case Type ct when ct == typeof(uint):
181                         r = BuildConstantExpression(rule, uint.Parse);
182                         break;
183                     case Type ct when ct == typeof(ulong):
184                         r = BuildConstantExpression(rule, ulong.Parse);
185                         break;
186 
187                     #endregion
188 
189                     #region 小數
190 
191                     case Type ct when ct == typeof(float):
192                         r = BuildConstantExpression(rule, float.Parse);
193                         break;
194                     case Type ct when ct == typeof(double):
195                         r = BuildConstantExpression(rule, double.Parse);
196                         break;
197                     case Type ct when ct == typeof(decimal):
198                         r = BuildConstantExpression(rule, decimal.Parse);
199                         break;
200 
201                     #endregion
202 
203                     #region 其它常用型別
204 
205                     case Type ct when ct == typeof(DateTime):
206                         r = BuildConstantExpression(rule, DateTime.Parse);
207                         break;
208                     case Type ct when ct == typeof(DateTimeOffset):
209                         r = BuildConstantExpression(rule, DateTimeOffset.Parse);
210                         break;
211                     case Type ct when ct == typeof(Guid):
212                         r = BuildConstantExpression(rule, Guid.Parse);
213                         break;
214                     case Type ct when ct.IsEnum:
215                         r = Expression.Constant(rule.Data.ToEnumObject(ct));
216                         break;
217 
218                     #endregion
219 
220                     default:
221                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的資料運算式");
222                 }
223             }
224 
225             if (r != null && pt.IsValueType && isNullable)
226             {
227                 var gt = typeof(Nullable<>).MakeGenericType(pt);
228                 r = Expression.Convert(r, gt);
229             }
230 
231             switch (rule.Op)
232             {
233                 case "eq": //等于
234                     e = Expression.Equal(l, r);
235                     break;
236                 case "ne": //不等于
237                     e = Expression.NotEqual(l, r);
238                     break;
239                 case "lt": //小于
240                     e = Expression.LessThan(l, r);
241                     break;
242                 case "le": //小于等于
243                     e = Expression.LessThanOrEqual(l, r);
244                     break;
245                 case "gt": //大于
246                     e = Expression.GreaterThan(l, r);
247                     break;
248                 case "ge": //大于等于
249                     e = Expression.GreaterThanOrEqual(l, r);
250                     break;
251                 case "bw": //開頭是(字串)
252                     if (pt == typeof(string))
253                     {
254                         e = Expression.Call(l, pt.GetMethod(nameof(string.StartsWith), new[] {typeof(string)}), r);
255                     }
256                     else
257                     {
258                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的開始于運算式");
259                     }
260 
261                     break;
262                 case "bn": //開頭不是(字串)
263                     if (pt == typeof(string))
264                     {
265                         e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.StartsWith), new[] {typeof(string)}), r));
266                     }
267                     else
268                     {
269                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的不開始于運算式");
270                     }
271 
272                     break;
273                 case "ew": //結尾是(字串)
274                     if (pt == typeof(string))
275                     {
276                         e = Expression.Call(l, pt.GetMethod(nameof(string.EndsWith), new[] {typeof(string)}), r);
277                     }
278                     else
279                     {
280                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的結束于運算式");
281                     }
282 
283                     break;
284                 case "en": //結尾不是(字串)
285                     if (pt == typeof(string))
286                     {
287                         e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.EndsWith), new[] {typeof(string)}), r));
288                     }
289                     else
290                     {
291                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的不結束于運算式");
292                     }
293 
294                     break;
295                 case "cn": //包含(字串)
296                     if (pt == typeof(string))
297                     {
298                         e = Expression.Call(l, pt.GetMethod(nameof(string.Contains), new[] {typeof(string)}), r);
299                     }
300                     else
301                     {
302                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的包含運算式");
303                     }
304 
305                     break;
306                 case "nc": //不包含(字串)
307                     if (pt == typeof(string))
308                     {
309                         e = Expression.Not(Expression.Call(l, pt.GetMethod(nameof(string.Contains), new[] {typeof(string)}), r));
310                     }
311                     else
312                     {
313                         throw new InvalidOperationException($"不支持創建{pt.FullName}型別的包含運算式");
314                     }
315 
316                     break;
317                 case "in": //屬于(是候選值串列之一)
318                     e = BuildContainsExpression(rule, l, pt);
319                     break;
320                 case "ni": //不屬于(不是候選值串列之一)
321                     e = Expression.Not(BuildContainsExpression(rule, l, pt));
322                     break;
323                 case "nu": //為空
324                     r = Expression.Constant(null);
325                     e = Expression.Equal(l, r);
326                     break;
327                 case "nn": //不為空
328                     r = Expression.Constant(null);
329                     e = Expression.Not(Expression.Equal(l, r));
330                     break;
331                 case "bt": //區間
332                     throw new NotImplementedException($"尚未實作創建{rule.Op}型別的比較運算式");
333                 default:
334                     throw new InvalidOperationException($"不支持創建{rule.Op}型別的比較運算式");
335             }
336 
337             return e;
338 
339             static Expression BuildConstantExpression<TValue>(JqGridSearchRule jRule, Func<string, TValue> valueConvertor)
340             {
341                 var rv = valueConvertor(jRule.Data);
342                 return Expression.Constant(rv);
343             }
344         }
345 
346         /// <summary>
347         /// 構造Contains呼叫運算式
348         /// </summary>
349         /// <param name="rule">條件</param>
350         /// <param name="parameter">引數</param>
351         /// <param name="parameterType">引數型別</param>
352         /// <returns>Contains呼叫運算式</returns>
353         private static Expression BuildContainsExpression(JqGridSearchRule rule, Expression parameter, Type parameterType)
354         {
355             Expression e = null;
356 
357             var genMethod = typeof(Queryable).GetMethods()
358                 .Single(m => m.Name == nameof(Queryable.Contains) && m.GetParameters().Length == 2);
359 
360             var jsonArray = JsonSerializer.Deserialize<string[]>(rule.Data);
361 
362             switch (parameterType)
363             {
364                 #region 文字
365 
366                 case Type ct when ct == typeof(char):
367                     if (jsonArray.Any(o => o.Length != 1)) {throw new InvalidOperationException("字符型的候選串列中存在錯誤的候選項");}
368                     e = CallContains(parameter, jsonArray, str => str[0], genMethod, ct);
369                     break;
370                 case Type ct when ct == typeof(string):
371                     e = CallContains(parameter, jsonArray, str => str, genMethod, ct);
372                     break;
373 
374                 #endregion
375 
376                 #region 有符號整數
377 
378                 case Type ct when ct == typeof(sbyte):
379                     e = CallContains(parameter, jsonArray, sbyte.Parse, genMethod, ct);
380                     break;
381                 case Type ct when ct == typeof(short):
382                     e = CallContains(parameter, jsonArray, short.Parse, genMethod, ct);
383                     break;
384                 case Type ct when ct == typeof(int):
385                     e = CallContains(parameter, jsonArray, int.Parse, genMethod, ct);
386                     break;
387                 case Type ct when ct == typeof(long):
388                     e = CallContains(parameter, jsonArray, long.Parse, genMethod, ct);
389                     break;
390 
391                 #endregion
392 
393                 #region 無符號整數
394 
395                 case Type ct when ct == typeof(byte):
396                     e = CallContains(parameter, jsonArray, byte.Parse, genMethod, ct);
397                     break;
398                 case Type ct when ct == typeof(ushort):
399                     e = CallContains(parameter, jsonArray, ushort.Parse, genMethod, ct);
400                     break;
401                 case Type ct when ct == typeof(uint):
402                     e = CallContains(parameter, jsonArray, uint.Parse, genMethod, ct);
403                     break;
404                 case Type ct when ct == typeof(ulong):
405                     e = CallContains(parameter, jsonArray, ulong.Parse, genMethod, ct);
406                     break;
407 
408                 #endregion
409 
410                 #region 小數
411 
412                 case Type ct when ct == typeof(float):
413                     e = CallContains(parameter, jsonArray, float.Parse, genMethod, ct);
414                     break;
415                 case Type ct when ct == typeof(double):
416                     e = CallContains(parameter, jsonArray, double.Parse, genMethod, ct);
417                     break;
418                 case Type ct when ct == typeof(decimal):
419                     e = CallContains(parameter, jsonArray, decimal.Parse, genMethod, ct);
420                     break;
421 
422                 #endregion
423 
424                 #region 其它常用型別
425 
426                 case Type ct when ct == typeof(DateTime):
427                     e = CallContains(parameter, jsonArray, DateTime.Parse, genMethod, ct);
428                     break;
429                 case Type ct when ct == typeof(DateTimeOffset):
430                     e = CallContains(parameter, jsonArray, DateTimeOffset.Parse, genMethod, ct);
431                     break;
432                 case Type ct when ct == typeof(Guid):
433                     e = CallContains(parameter, jsonArray, Guid.Parse, genMethod, ct);
434                     break;
435                 case Type ct when ct.IsEnum:
436                     e = CallContains(Expression.Convert(parameter, typeof(object)), jsonArray, enumString => enumString.ToEnumObject(ct), genMethod, ct);
437                     break;
438 
439                     #endregion
440             }
441 
442             return e;
443 
444             static MethodCallExpression CallContains<T>(Expression pa, string[] jArray, Func<string, T> selector, MethodInfo genericMethod, Type type)
445             {
446                 var data =https://www.cnblogs.com/coredx/p/ jArray.Select(selector).ToArray().AsQueryable();
447                 var method = genericMethod.MakeGenericMethod(type);
448 
449                 return Expression.Call(null, method, new[] { Expression.Constant(data), pa });
450             }
451         }
452     }

使用

       此處是在 Razor Page 中使用,內部使用的其他輔助類和前端頁面代碼就不貼了,有興趣的可以在我的文章末尾找到 GitHub 專案鏈接:

 1         public async Task<IActionResult> OnGetUserListAsync([FromQuery]JqGridParameter jqGridParameter)
 2         {
 3             var usersQuery = _userManager.Users.AsNoTracking();
 4             if (jqGridParameter._search == "true")
 5             {
 6                 usersQuery = usersQuery.Where(BuildWhere<ApplicationUser>(jqGridParameter.FilterObject, null));
 7             }
 8 
 9             var users = usersQuery.Include(u => u.UserRoles).ThenInclude(ur => ur.Role).OrderBy(u => u.InsertOrder)
10                 .Skip((jqGridParameter.Page - 1) * jqGridParameter.Rows).Take(jqGridParameter.Rows).ToList();
11             var userCount = usersQuery.Count();
12             var pageCount = Ceiling((double) userCount / jqGridParameter.Rows);
13             return new JsonResult(
14                 new
15                 {
16                     rows //資料集合
17                         = users.Select(u => new
18                         {
19                             u.UserName,
20                             u.Gender,
21                             u.Email,
22                             u.PhoneNumber,
23                             u.EmailConfirmed,
24                             u.PhoneNumberConfirmed,
25                             u.CreationTime,
26                             u.CreatorId,
27                             u.Active,
28                             u.LastModificationTime,
29                             u.LastModifierId,
30                             u.InsertOrder,
31                             u.ConcurrencyStamp,
32                             //以下為JqGrid中必須的欄位
33                             u.Id //記錄的唯一標識,可在插件中配置為其它欄位,但是必須能作為記錄的唯一標識用,不能重復
34                         }),
35                     total = pageCount, //總頁數
36                     page = jqGridParameter.Page, //當前頁碼
37                     records = userCount //總記錄數
38                 }
39             );
40         }

       啟動專案后訪問 /Identity/Manage/Users/Index 可以嘗試使用,

結語

       通過這次實踐,深入了解了很多運算式樹的相關知識,運算式樹在編譯流程中還算是高級結構了,耐點心還是能看懂,IL 才是真的暈,比原生匯編也好不到哪里去,C# 確實很有意思,入門簡單,內部卻深邃無比,在小白和大神手上完全是兩種語言,Java 在 Java 8 時增加了 Stream 和 Lambda 運算式功能,一看就是在對標 Linq,不過那名字取的真是一言難盡,看代碼寫代碼感覺如鯁在喉,相當不爽,由于 Stream 體系缺少運算式樹,這種動態構造查詢運算式的功能從一開始就不可能支持,再加上 Java 沒有匿名型別,沒有物件初始化器,每次用 Stream 就難受的一批,中間程序的資料結構也要專門寫類,每個中間類還要獨占一個檔案,簡直暈死,抄都抄不及格!

       C# 引入 var 關鍵字核心是為匿名型別服務,畢竟是編譯器自動生成的型別,寫代碼的時候根本沒有名字,不用 var 用什么?簡化變數初始化代碼只是順帶的,結果 Java 又抄一半,還是最不打緊的一半,簡化變數初始化代碼,真不知道搞 Java 的那幫人在想些什么,

 

       轉載請完整保留以下內容并在顯眼位置標注,未經授權洗掉以下內容進行轉載盜用的,保留追究法律責任的權利!

  本文地址:https://www.cnblogs.com/coredx/p/12423929.html

  完整源代碼:Github

  里面有各種小東西,這只是其中之一,不嫌棄的話可以Star一下,

轉載請註明出處,本文鏈接:https://www.uj5u.com/net/64876.html

標籤:C#

上一篇:[WinApi] C#獲取其他視窗文本框內容

下一篇:關于“Failed to complete setup of assembly(hr = 0x80131040). Probing terminated”

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • WebAPI簡介

    Web體系結構: 有三個核心:資源(resource),URL(統一資源識別符號)和表示 他們的關系是這樣的:一個資源由一個URL進行標識,HTTP客戶端使用URL定位資源,表示是從資源回傳資料,媒體型別是資源回傳的資料格式。 接下來我們說下HTTP. HTTP協議的系統是一種無狀態的方式,使用請求/ ......

    uj5u.com 2020-09-09 22:07:47 more
  • asp.net core 3.1 入口:Program.cs中的Main函式

    本文分析Program.cs 中Main()函式中代碼的運行順序分析asp.net core程式的啟動,重點不是剖析原始碼,而是理清程式開始時執行的順序。到呼叫了哪些實體,哪些法方。asp.net core 3.1 的程式入口在專案Program.cs檔案里,如下。ususing System; us ......

    uj5u.com 2020-09-09 22:07:49 more
  • asp.net網站作為websocket服務端的應用該如何寫

    最近被websocket的一個問題困擾了很久,有一個需求是在web網站中搭建websocket服務。客戶端通過網頁與服務器建立連接,然后服務器根據ip給客戶端網頁發送資訊。 其實,這個需求并不難,只是剛開始對websocket的內容不太了解。上網搜索了一下,有通過asp.net core 實作的、有 ......

    uj5u.com 2020-09-09 22:08:02 more
  • ASP.NET 開源匯入匯出庫Magicodes.IE Docker中使用

    Magicodes.IE在Docker中使用 更新歷史 2019.02.13 【Nuget】版本更新到2.0.2 【匯入】修復單列匯入的Bug,單元測驗“OneColumnImporter_Test”。問題見(https://github.com/dotnetcore/Magicodes.IE/is ......

    uj5u.com 2020-09-09 22:08:05 more
  • 在webform中使用ajax

    如果你用過Asp.net webform, 說明你也算是.NET 開發的老兵了。WEBform應該是2011 2013左右,當時還用visual studio 2005、 visual studio 2008。后來基本都用的是MVC。 如果是新開發的專案,估計沒人會用webform技術。但是有些舊版 ......

    uj5u.com 2020-09-09 22:08:50 more
  • iis添加asp.net網站,訪問提示:由于擴展配置問題而無法提供您請求的

    今天在iis服務器配置asp.net網站,遇到一個問題,記錄一下: 問題:由于擴展配置問題而無法提供您請求的頁面。如果該頁面是腳本,請添加處理程式。如果應下載檔案,請添加 MIME 映射。 WindowServer2012服務器,添加角色安裝完.netframework和iis之后,運行aspx頁面 ......

    uj5u.com 2020-09-09 22:10:00 more
  • WebAPI-處理架構

    帶著問題去思考,大家好! 問題1:HTTP請求和回傳相應的HTTP回應資訊之間發生了什么? 1:首先是最底層,托管層,位于WebAPI和底層HTTP堆疊之間 2:其次是 訊息處理程式管道層,這里比如日志和快取。OWIN的參考是將訊息處理程式管道的一些功能下移到堆疊下端的OWIN中間件了。 3:控制器處理 ......

    uj5u.com 2020-09-09 22:11:13 more
  • 微信門戶開發框架-使用指導說明書

    微信門戶應用管理系統,采用基于 MVC + Bootstrap + Ajax + Enterprise Library的技術路線,界面層采用Boostrap + Metronic組合的前端框架,資料訪問層支持Oracle、SQLServer、MySQL、PostgreSQL等資料庫。框架以MVC5,... ......

    uj5u.com 2020-09-09 22:15:18 more
  • WebAPI-HTTP編程模型

    帶著問題去思考,大家好!它是什么?它包含什么?它能干什么? 訊息 HTTP編程模型的核心就是訊息抽象,表示為:HttPRequestMessage,HttpResponseMessage.用于客戶端和服務端之間交換請求和回應訊息。 HttpMethod類包含了一組靜態屬性: private stat ......

    uj5u.com 2020-09-09 22:15:23 more
  • 部署WebApi隨筆

    一、跨域 NuGet參考Microsoft.AspNet.WebApi.Cors WebApiConfig.cs中配置: // Web API 配置和服務 config.EnableCors(new EnableCorsAttribute("*", "*", "*")); 二、清除默認回傳XML格式 ......

    uj5u.com 2020-09-09 22:15:48 more
最新发布
  • C#多執行緒學習(二) 如何操縱一個執行緒

    <a href="https://www.cnblogs.com/x-zhi/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2943582/20220801082530.png" alt="" /></...

    uj5u.com 2023-04-19 09:17:20 more
  • C#多執行緒學習(二) 如何操縱一個執行緒

    C#多執行緒學習(二) 如何操縱一個執行緒 執行緒學習第一篇:C#多執行緒學習(一) 多執行緒的相關概念 下面我們就動手來創建一個執行緒,使用Thread類創建執行緒時,只需提供執行緒入口即可。(執行緒入口使程式知道該讓這個執行緒干什么事) 在C#中,執行緒入口是通過ThreadStart代理(delegate)來提供的 ......

    uj5u.com 2023-04-19 09:16:49 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    <a href="https://www.cnblogs.com/huangxincheng/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/214741/20200614104537.png" alt="" /&g...

    uj5u.com 2023-04-18 08:39:04 more
  • 記一次 .NET某醫療器械清洗系統 卡死分析

    一:背景 1. 講故事 前段時間協助訓練營里的一位朋友分析了一個程式卡死的問題,回過頭來看這個案例比較經典,這篇稍微整理一下供后來者少踩坑吧。 二:WinDbg 分析 1. 為什么會卡死 因為是表單程式,理所當然就是看主執行緒此時正在做什么? 可以用 ~0s ; k 看一下便知。 0:000> k # ......

    uj5u.com 2023-04-18 08:33:10 more
  • SignalR, No Connection with that ID,IIS

    <a href="https://www.cnblogs.com/smartstar/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/u36196.jpg" alt="" /></a>...

    uj5u.com 2023-03-30 17:21:52 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:15:33 more
  • 一次對pool的誤用導致的.net頻繁gc的診斷分析

    <a href="https://www.cnblogs.com/dotnet-diagnostic/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/3115652/20230225090434.png" alt=""...

    uj5u.com 2023-03-28 10:13:31 more
  • C#遍歷指定檔案夾中所有檔案的3種方法

    <a href="https://www.cnblogs.com/xbhp/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/957602/20230310105611.png" alt="" /></a&...

    uj5u.com 2023-03-27 14:46:55 more
  • C#/VB.NET:如何將PDF轉為PDF/A

    <a href="https://www.cnblogs.com/Carina-baby/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/2859233/20220427162558.png" alt="" />...

    uj5u.com 2023-03-27 14:46:35 more
  • 武裝你的WEBAPI-OData聚合查詢

    <a href="https://www.cnblogs.com/podolski/" target="_blank"><img width="48" height="48" class="pfs" src="https://pic.cnblogs.com/face/616093/20140323000327.png" alt="" /><...

    uj5u.com 2023-03-27 14:46:16 more