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

Commit 566adce

Browse files
committed
you can modify value if return a new value
1 parent 833dae8 commit 566adce

30 files changed

+1125
-72
lines changed

README.md

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,11 @@ order.FormatToString();
4747

4848
## API
4949

50-
| icon | remark |
51-
| ---- | ----------------------------------------------------------- |
52-
| ✔️ | it is already avaliable in latest version |
53-
| 🚧 | still in plan or development and will be changed or removed |
54-
|| it is removed form the latest version |
50+
| icon | remark |
51+
| ---- | ------------------------------------------------------------------------ |
52+
| ✔️ | it is already avaliable in latest version |
53+
| 🚧 | still in plan or development and will be implemented, changed or removed |
54+
|| it is removed form the latest version |
5555

5656
```cs
5757
var o = new Yueluo();
@@ -97,8 +97,9 @@ var cachedVisitor = deafult(Yueluo).V()
9797
cachedVisitor.Run(new Yueluo(), new StringBuilder());
9898

9999

100-
//🚧 you can modify value if return a new value
101-
o.V().ForEach((context)=>context.Value.SubString(0,1)).Run();
100+
//✔️ from 0.2
101+
// you can modify value if return a new value
102+
o.V().ForEach((context)=>context.Value = context.Value.SubString(0,1)).Run();
102103

103104
//✔️ from 0.1
104105
// get debug info about expression now

src/Directory.Build.props

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,4 +70,7 @@ Why do I need this?
7070
<PackageReference Include="Autofac.Extras.Moq" Version="4.3.0"/>
7171
<PackageReference Include="FluentAssertions" Version="5.10.3"/>
7272
</ItemGroup>
73+
<ItemGroup Condition=" '$(Configuration)' == 'Debug' ">
74+
<PackageReference Include="AgileObjects.ReadableExpressions" Version="2.5.1" />
75+
</ItemGroup>
7376
</Project>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
using System;
2+
using System.Reflection;
3+
using BenchmarkDotNet.Attributes;
4+
5+
namespace Newbe.ObjectVisitor.BenchmarkTest
6+
{
7+
[Config(typeof(Config))]
8+
public class PropertyGetterTest
9+
{
10+
private readonly Yueluo _yueluo;
11+
private readonly PropertyInfo _nameProperty;
12+
private readonly PropertyInfo _ageProperty;
13+
private readonly Func<Yueluo, string> _nameFunc;
14+
15+
public PropertyGetterTest()
16+
{
17+
_yueluo = Yueluo.Create();
18+
_nameProperty = typeof(Yueluo).GetProperty(nameof(Yueluo.Name));
19+
_ageProperty = typeof(Yueluo).GetProperty(nameof(Yueluo.Age));
20+
_nameFunc = ValueGetter<Yueluo, string, string>.GetGetter(_nameProperty);
21+
_ = ValueGetter<Yueluo, int, int>.GetGetter(_ageProperty).Invoke(_yueluo);
22+
_ = ValueGetter<Yueluo>.GetGetter(_nameProperty).Invoke(_yueluo);
23+
}
24+
25+
[Benchmark(Baseline = true)]
26+
public string DirectlyString() => _yueluo.Name;
27+
28+
[Benchmark]
29+
public int DirectlyInt() => _yueluo.Age;
30+
31+
[Benchmark]
32+
public string ReflectString() => (string) _nameProperty.GetValue(_yueluo);
33+
34+
[Benchmark]
35+
public int ReflectInt() => (int) _ageProperty.GetValue(_yueluo);
36+
37+
[Benchmark]
38+
public string GetterString()
39+
=> ValueGetter<Yueluo, string, string>.GetGetter(_nameProperty).Invoke(_yueluo);
40+
41+
[Benchmark]
42+
public int GetterInt()
43+
=> ValueGetter<Yueluo, int, int>.GetGetter(_ageProperty).Invoke(_yueluo);
44+
45+
[Benchmark]
46+
public string GetterObject()
47+
=> (string) ValueGetter<Yueluo>.GetGetter(_nameProperty).Invoke(_yueluo);
48+
49+
[Benchmark]
50+
public string GetterCached()
51+
=> _nameFunc.Invoke(_yueluo);
52+
}
53+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System.Text.RegularExpressions;
2+
using FluentAssertions;
3+
using NUnit.Framework;
4+
5+
namespace Newbe.ObjectVisitor.Tests
6+
{
7+
public class ChangePasswordTest
8+
{
9+
[Test]
10+
public void CoverSensitiveDataTest()
11+
{
12+
// here is a model
13+
var userModel = new UserModel
14+
{
15+
Username = "newbe36524",
16+
Password = "newbe.pro",
17+
Phone = "12345678901"
18+
};
19+
20+
// create a data visitor to cover sensitive data
21+
var visitor = userModel.V()
22+
.ForEach<UserModel, string>(x => CoverSensitiveData(x))
23+
.Cache();
24+
25+
visitor.Run(userModel);
26+
27+
var expected = new UserModel
28+
{
29+
Username = "newbe36524",
30+
Password = "***",
31+
Phone = "123****8901",
32+
};
33+
userModel.Should().BeEquivalentTo(expected);
34+
}
35+
36+
private void CoverSensitiveData(IObjectVisitorContext<UserModel, string> c)
37+
{
38+
var value = c.Value;
39+
if (!string.IsNullOrEmpty(value))
40+
{
41+
c.Value = Regex.Replace(value, "(\\d{3})\\d{4}(\\d{4})", "$1****$2");
42+
}
43+
44+
if (c.Name == nameof(UserModel.Password))
45+
{
46+
c.Value = "***";
47+
}
48+
}
49+
50+
public class UserModel
51+
{
52+
public string Username { get; set; } = null!;
53+
public string Phone { get; set; } = null!;
54+
public string Password { get; set; } = null!;
55+
}
56+
}
57+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System.Collections.Generic;
2+
using System.ComponentModel;
3+
using System.Linq;
4+
using System.Text;
5+
using FluentAssertions;
6+
using NUnit.Framework;
7+
8+
namespace Newbe.ObjectVisitor.Tests
9+
{
10+
public class DataConnectionModelTest
11+
{
12+
public const string ConnectionStringValue =
13+
"Host=www.newbe.pro;Port=36524;Username=newbe36524;Password=newbe.pro;";
14+
15+
[Test]
16+
public void JoinToString()
17+
{
18+
var model = new DataConnectionModel
19+
{
20+
Host = "www.newbe.pro",
21+
Port = 36524,
22+
Username = "newbe36524",
23+
Password = "newbe.pro",
24+
};
25+
var connectionString = model.ToString();
26+
27+
connectionString.Should().Be(ConnectionStringValue);
28+
}
29+
30+
[Test]
31+
public void BuildFromString()
32+
{
33+
var model = DataConnectionModel.FromString(ConnectionStringValue);
34+
var expected = new DataConnectionModel
35+
{
36+
Host = "www.newbe.pro",
37+
Port = 36524,
38+
Username = "newbe36524",
39+
Password = "newbe.pro",
40+
};
41+
model.Should().BeEquivalentTo(expected);
42+
}
43+
44+
45+
public class DataConnectionModel
46+
{
47+
public string Host { get; set; } = null!;
48+
public ushort? Port { get; set; } = null!;
49+
public string Username { get; set; } = null!;
50+
public string Password { get; set; } = null!;
51+
public int? MaxPoolSize { get; set; } = null!;
52+
53+
private static readonly ICachedObjectVisitor<DataConnectionModel, StringBuilder> ConnectionStringBuilder =
54+
default(DataConnectionModel)!
55+
.V()
56+
.WithExtendObject<DataConnectionModel, StringBuilder>()
57+
.ForEach((name, value, sb) => AppendValueIfNotNull(name, value, sb))
58+
.Cache();
59+
60+
private static void AppendValueIfNotNull(string name, object? value, StringBuilder sb)
61+
{
62+
if (value != null)
63+
{
64+
sb.Append($"{name}={value};");
65+
}
66+
}
67+
68+
69+
public override string ToString()
70+
{
71+
var sb = new StringBuilder();
72+
ConnectionStringBuilder.Run(this, sb);
73+
return sb.ToString();
74+
}
75+
76+
private static readonly ICachedObjectVisitor<DataConnectionModel, Dictionary<string, string>>
77+
ConnectionStringConstructor
78+
=
79+
default(DataConnectionModel)!
80+
.V()
81+
.WithExtendObject<DataConnectionModel, Dictionary<string, string>>()
82+
.ForEach(context => SetValueIfFound(context))
83+
.Cache();
84+
85+
private static void SetValueIfFound(
86+
IObjectVisitorContext<DataConnectionModel, Dictionary<string, string>, object> c)
87+
{
88+
if (c.ExtendObject.TryGetValue(c.Name, out var stringValue))
89+
{
90+
TypeConverter conv = TypeDescriptor.GetConverter(c.PropertyInfo.PropertyType);
91+
c.Value = conv.ConvertFrom(stringValue)!;
92+
}
93+
}
94+
95+
public static DataConnectionModel FromString(string connectionString)
96+
{
97+
var dic = connectionString.Split(';')
98+
.Where(x => !string.IsNullOrEmpty(x))
99+
.Select(x => x.Split('='))
100+
.ToDictionary(x => x[0], x => x[1]);
101+
var re = new DataConnectionModel();
102+
ConnectionStringConstructor.Run(re, dic);
103+
return re;
104+
}
105+
}
106+
}
107+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
using System.Collections.Generic;
2+
using System.Linq;
3+
using FluentAssertions;
4+
using NUnit.Framework;
5+
6+
namespace Newbe.ObjectVisitor.Tests
7+
{
8+
public class EnumerableTest
9+
{
10+
[Test]
11+
public void NameAndValue()
12+
{
13+
var model = new TestModel
14+
{
15+
List1 = new[] {1},
16+
List2 = new[] {2},
17+
List3 = new List<int> {3},
18+
List4 = new HashSet<int> {4}
19+
};
20+
var sumBag = new SumBag();
21+
var visitor = model.V()
22+
.WithExtendObject(sumBag)
23+
.ForEach<TestModel, SumBag, IEnumerable<int>>((name, value, bag) => Sum(bag, value),
24+
x => x.IsOrImplOf<IEnumerable<int>>())
25+
.Cache();
26+
visitor.Run(model, sumBag);
27+
sumBag.Sum.Should().Be(10);
28+
}
29+
30+
[Test]
31+
public void NameAndValue2()
32+
{
33+
var model = new TestModel
34+
{
35+
List1 = new[] {1},
36+
List2 = new[] {2},
37+
List3 = new List<int> {3},
38+
List4 = new HashSet<int> {4}
39+
};
40+
var sumBag = new SumBag();
41+
var visitor = model.V()
42+
.WithExtendObject(sumBag)
43+
.ForEach<TestModel, SumBag, IEnumerable<int>>(x => Sum(x.ExtendObject, x.Value),
44+
x => x.IsOrImplOf<IEnumerable<int>>())
45+
.Cache();
46+
visitor.Run(model, sumBag);
47+
sumBag.Sum.Should().Be(10);
48+
}
49+
50+
private static void Sum(SumBag bag, IEnumerable<int> data)
51+
{
52+
bag.Sum += data.Sum();
53+
}
54+
55+
public class SumBag
56+
{
57+
public int Sum { get; set; }
58+
}
59+
60+
public class TestModel
61+
{
62+
public int[] List1 { get; set; } = null!;
63+
public IEnumerable<int> List2 { get; set; } = null!;
64+
public List<int> List3 { get; set; } = null!;
65+
public HashSet<int> List4 { get; set; } = null!;
66+
}
67+
}
68+
}

0 commit comments

Comments
 (0)