Skip to content
This repository was archived by the owner on Sep 7, 2021. It is now read-only.

Commit 071dc41

Browse files
committed
- Add README_zh_Hans.md
- Add more benchmark test
1 parent 566adce commit 071dc41

File tree

12 files changed

+722
-39
lines changed

12 files changed

+722
-39
lines changed

README.md

Lines changed: 86 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
# Newbe.ObjectVisitor
22

3+
- [简体中文](README_zh_Hans.md)
4+
- [English](README.md)
5+
36
![Banner](https://github.com/newbe36524/Newbe.ObjectVisitor/raw/docs/assets/banner.svg)
47

5-
You can visit all properties about your class or struct by this lib with high performance as you visit properties in hard coding way.
8+
You can visit all properties about your class by this lib with high performance as you visit properties in hard coding way.
69

710
For example, here is object in your code.
811

@@ -41,9 +44,9 @@ order.FormatToString();
4144

4245
## Why do I need this?
4346

44-
- It is faster. This lib is impletmented with [Expression Trees](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/) that cost 1/10 time as in Reflection way.
45-
- It is readable. This lib can generate a lambda func to handle the code flow you create that just as your hard coding without reflection.
46-
- It is extendable. If you can visit all properties of a object in easy way, you can validate them as you wish, change some value if there are something sensitive, creare a mapper like automapper, and etc.
47+
- **It is faster.** This lib is impletmented with [Expression Trees](https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/expression-trees/) that cost 1/10 time as in Reflection way.
48+
- **It is readable.** This lib can generate a lambda func to handle the code flow you create that just as your hard coding without reflection.
49+
- **It is extendable.** If you can visit all properties of a object in easy way, you can validate them as you wish, change some value if there are something sensitive, creare a mapper like automapper, and etc.
4750

4851
## API
4952

@@ -73,6 +76,11 @@ var visitor = typeof(Yueluo).V();
7376
o.V().ForEach((context)=>{}).Run();
7477
o.V().ForEach((name,value)=>{}).Run();
7578

79+
// ✔️ from 0.2
80+
// multiple foreach
81+
o.V().ForEach((context)=>{}).ForEach((context)=>{}).Run();
82+
83+
7684
//✔️ from 0.1
7785
// create a visitor with extend object as parameter
7886
o.V().WithExtendObject<Yueluo, StringBuilder>()
@@ -99,7 +107,12 @@ cachedVisitor.Run(new Yueluo(), new StringBuilder());
99107

100108
//✔️ from 0.2
101109
// you can modify value if return a new value
102-
o.V().ForEach((context)=>context.Value = context.Value.SubString(0,1)).Run();
110+
o.V().ForEach((context) => ModifyDatacontext)).Run();
111+
112+
public static void ModifyData(IObjectVisitorContext<Yueluo,string> context)
113+
{
114+
context.Value = context.Value.SubString(0,1);
115+
}
103116

104117
//✔️ from 0.1
105118
// get debug info about expression now
@@ -113,8 +126,17 @@ var code = o.V().ForEach((context)=>{}).GenerateCode();
113126
var func = o.V().ForEach((context)=>{}).GetLambda();
114127

115128

116-
//🚧 foreach properties with specified type
117-
o.V().ForEach<string>((context)=>{}).Run();
129+
//✔️ from 0.2
130+
// foreach properties with specified type
131+
o.V().ForEach<Yueluo, string>((context) => {});
132+
// the same as above
133+
o.V().ForEach<Yueluo, string>((context) => {}, x => x.PropertyType == typeof(string));
134+
// foreach properties with string type and marked with RequiredAttribute
135+
o.V().ForEach<Yueluo, string>((context) => {}, x => x.PropertyType == typeof(string) && x.GetCustomAttribute<RequiredAttribute>());
136+
// foreach properties that implemented IEnumerable<int> ,such as List<int>, int[], IEnumerable<int>, HashSet<int> and etc.
137+
o.V().ForEach<Yueluo, IEnumerable<int>>((context) => {}, x => x.IsOrImplOf<IEnumerable<int>>());
138+
// with extend object as parameter
139+
o.V().WithExtendObject<Yueluo, StringBuilder>().ForEach<Yueluo, StringBuilder, string>((context) => {});
118140

119141
//🚧 using linq to filter
120142
o.V().AsEnumerable().Where((context)=>context.Name == "YueLuo").ForEach((context)=>{}).Run();
@@ -216,7 +238,6 @@ o.V().SuppendAttributeValidation()
216238
).Run();
217239

218240
// 🚧suppending sub-object validation
219-
// validate whole object
220241
o.V().SuppendSubObject()
221242
.SuppendAttributeValidation()
222243
.Validate(v=>
@@ -285,27 +306,27 @@ chart:
285306

286307
data:
287308

288-
| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Rank |
289-
| ------------ | ------------ | ------------- | ---------: | -------: | -------: | ----: | ------: | ---: |
290-
| Directly | net461 | .NET 4.6.1 | 758.7 ns | 4.60 ns | 4.30 ns | 1.00 | 0.00 | 1 |
291-
| CacheVisitor | net461 | .NET 4.6.1 | 810.3 ns | 3.26 ns | 2.89 ns | 1.07 | 0.01 | 2 |
292-
| QuickStyle | net461 | .NET 4.6.1 | 1,095.6 ns | 16.86 ns | 15.77 ns | 1.44 | 0.02 | 3 |
293-
| | | | | | | | | |
294-
| Directly | net48 | .NET 4.8 | 760.5 ns | 2.79 ns | 2.61 ns | 1.00 | 0.00 | 1 |
295-
| CacheVisitor | net48 | .NET 4.8 | 814.3 ns | 5.11 ns | 4.53 ns | 1.07 | 0.01 | 2 |
296-
| QuickStyle | net48 | .NET 4.8 | 1,079.0 ns | 5.98 ns | 5.30 ns | 1.42 | 0.01 | 3 |
297-
| | | | | | | | | |
298-
| Directly | netcoreapp21 | .NET Core 2.1 | 800.7 ns | 3.26 ns | 2.89 ns | 1.00 | 0.00 | 1 |
299-
| CacheVisitor | netcoreapp21 | .NET Core 2.1 | 809.7 ns | 3.65 ns | 3.04 ns | 1.01 | 0.00 | 1 |
300-
| QuickStyle | netcoreapp21 | .NET Core 2.1 | 1,141.3 ns | 6.88 ns | 6.10 ns | 1.43 | 0.01 | 2 |
301-
| | | | | | | | | |
302-
| Directly | netcoreapp31 | .NET Core 3.1 | 679.0 ns | 2.53 ns | 1.97 ns | 1.00 | 0.00 | 1 |
303-
| CacheVisitor | netcoreapp31 | .NET Core 3.1 | 679.4 ns | 5.38 ns | 4.77 ns | 1.00 | 0.01 | 1 |
304-
| QuickStyle | netcoreapp31 | .NET Core 3.1 | 936.2 ns | 6.09 ns | 5.40 ns | 1.38 | 0.01 | 2 |
305-
| | | | | | | | | |
306-
| Directly | netcoreapp5 | .NET Core 5.0 | 676.5 ns | 6.60 ns | 6.17 ns | 1.00 | 0.00 | 2 |
307-
| CacheVisitor | netcoreapp5 | .NET Core 5.0 | 654.2 ns | 4.07 ns | 3.61 ns | 0.97 | 0.01 | 1 |
308-
| QuickStyle | netcoreapp5 | .NET Core 5.0 | 860.1 ns | 5.99 ns | 5.31 ns | 1.27 | 0.01 | 3 |
309+
| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Rank |
310+
| ------------ | ------------ | ------------- | -------: | -------: | -------: | ----: | ------: | ---: |
311+
| Directly | net461 | .NET 4.6.1 | 754.3 ns | 8.49 ns | 7.94 ns | 1.00 | 0.00 | 1 |
312+
| QuickStyle | net461 | .NET 4.6.1 | 818.3 ns | 16.29 ns | 24.87 ns | 1.10 | 0.04 | 3 |
313+
| CacheVisitor | net461 | .NET 4.6.1 | 791.4 ns | 11.62 ns | 10.30 ns | 1.05 | 0.01 | 2 |
314+
| | | | | | | | | |
315+
| Directly | net48 | .NET 4.8 | 738.5 ns | 7.37 ns | 6.90 ns | 1.00 | 0.00 | 1 |
316+
| QuickStyle | net48 | .NET 4.8 | 799.0 ns | 10.63 ns | 9.42 ns | 1.08 | 0.01 | 2 |
317+
| CacheVisitor | net48 | .NET 4.8 | 788.0 ns | 8.27 ns | 6.91 ns | 1.07 | 0.02 | 2 |
318+
| | | | | | | | | |
319+
| Directly | netcoreapp21 | .NET Core 2.1 | 768.6 ns | 9.63 ns | 9.01 ns | 1.00 | 0.00 | 1 |
320+
| QuickStyle | netcoreapp21 | .NET Core 2.1 | 787.6 ns | 6.11 ns | 5.42 ns | 1.02 | 0.02 | 2 |
321+
| CacheVisitor | netcoreapp21 | .NET Core 2.1 | 768.6 ns | 5.30 ns | 4.96 ns | 1.00 | 0.01 | 1 |
322+
| | | | | | | | | |
323+
| Directly | netcoreapp31 | .NET Core 3.1 | 659.4 ns | 6.64 ns | 5.88 ns | 1.00 | 0.00 | 1 |
324+
| QuickStyle | netcoreapp31 | .NET Core 3.1 | 685.1 ns | 8.25 ns | 7.72 ns | 1.04 | 0.01 | 2 |
325+
| CacheVisitor | netcoreapp31 | .NET Core 3.1 | 655.6 ns | 5.90 ns | 5.52 ns | 0.99 | 0.01 | 1 |
326+
| | | | | | | | | |
327+
| Directly | netcoreapp5 | .NET Core 5.0 | 624.2 ns | 3.59 ns | 3.00 ns | 1.00 | 0.00 | 2 |
328+
| QuickStyle | netcoreapp5 | .NET Core 5.0 | 641.2 ns | 5.60 ns | 4.97 ns | 1.03 | 0.01 | 3 |
329+
| CacheVisitor | netcoreapp5 | .NET Core 5.0 | 604.2 ns | 8.19 ns | 7.66 ns | 0.97 | 0.01 | 1 |
309330

310331
summary:
311332

@@ -353,6 +374,42 @@ summary:
353374
1. It will cost much more time to build a ObjectVisitor, since it will take more time to build more object and reflection. So we suggest to use build ObjectVisitor and cache it. You can still create a un-cached object visitor in cold code path since it take less then 1 ms.
354375
2. A Cache visitor is faster than reflection way.
355376

377+
### Modify Data with Condition
378+
379+
Maybe you want to replace a property named Password with '\*\*\*' in you object. That string will be done by methods below:
380+
381+
| Method | Descrption |
382+
| ------------ | ------------------------------------------------------------------------------------------------------------------- |
383+
| Directly | Modify data directly with assign statement |
384+
| UsingVisitor | Build a ObjectVisitor with Newbe.ObjectVisitor and cache it into a field. Using that cached visitor to modify info. |
385+
386+
chart:
387+
388+
![Newbe.ObjectVisitor.BenchmarkTest.ChangePasswordTest-barplot](https://github.com/newbe36524/Newbe.ObjectVisitor/raw/docs/assets/Newbe.ObjectVisitor.BenchmarkTest.ChangePasswordTest-barplot.png)
389+
390+
data:
391+
392+
| Method | Job | Runtime | Mean | Error | StdDev | Ratio | RatioSD | Rank |
393+
| ------------ | ------------ | ------------- | ---------: | -------: | -------: | ----: | ------: | ---: |
394+
| Directly | net461 | .NET 4.6.1 | 1,205.4 ns | 8.90 ns | 7.44 ns | 1.00 | 0.00 | 1 |
395+
| UsingVisitor | net461 | .NET 4.6.1 | 3,807.0 ns | 68.28 ns | 63.87 ns | 3.15 | 0.04 | 2 |
396+
| | | | | | | | | |
397+
| Directly | net48 | .NET 4.8 | 1,205.9 ns | 5.74 ns | 5.08 ns | 1.00 | 0.00 | 1 |
398+
| UsingVisitor | net48 | .NET 4.8 | 3,743.3 ns | 18.51 ns | 15.46 ns | 3.11 | 0.02 | 2 |
399+
| | | | | | | | | |
400+
| Directly | netcoreapp21 | .NET Core 2.1 | 999.3 ns | 7.28 ns | 6.08 ns | 1.00 | 0.00 | 1 |
401+
| UsingVisitor | netcoreapp21 | .NET Core 2.1 | 2,882.4 ns | 9.58 ns | 8.96 ns | 2.89 | 0.02 | 2 |
402+
| | | | | | | | | |
403+
| Directly | netcoreapp31 | .NET Core 3.1 | 807.9 ns | 3.46 ns | 3.07 ns | 1.00 | 0.00 | 1 |
404+
| UsingVisitor | netcoreapp31 | .NET Core 3.1 | 2,614.1 ns | 13.79 ns | 12.90 ns | 3.24 | 0.02 | 2 |
405+
| | | | | | | | | |
406+
| Directly | netcoreapp5 | .NET Core 5.0 | 533.8 ns | 1.72 ns | 1.44 ns | 1.00 | 0.00 | 1 |
407+
| UsingVisitor | netcoreapp5 | .NET Core 5.0 | 1,398.0 ns | 9.24 ns | 8.19 ns | 2.62 | 0.02 | 2 |
408+
409+
summary:
410+
411+
1. It will take 1000-3000 ns more to modify data by visitor. So you can take this way if you think it is acceptable in your case.
412+
356413
### validate vs FluentValidation
357414

358415
TODO

0 commit comments

Comments
 (0)