Skip to content

Commit db88e82

Browse files
committed
MagicObject v0.0.2 将 MO.OriginObject 和 MO.Object 属性设为 public。完善并通过单元测试
1 parent adee91b commit db88e82

File tree

5 files changed

+236
-19
lines changed

5 files changed

+236
-19
lines changed

src/Senparc.CO2NET.MagicObject.Tests/MoTests.cs

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System;
44
using System.Collections.Generic;
55
using System.Linq.Expressions;
6+
using System.Xml.Linq;
67

78
namespace Senparc.CO2NET.MagicObject.Tests
89
{
@@ -28,11 +29,50 @@ public void Setup()
2829
[TestMethod]
2930
public void Set_SingleProperty_ChangesTracked()
3031
{
32+
var dt = SystemTime.Now;
33+
3134
_mo.Set(p => p.Name, "Bob");
3235

36+
var dt0 = SystemTime.Now;
37+
3338
var result = _mo.Get(p => p.Name);
39+
40+
var dt1 = SystemTime.Now;
41+
42+
Console.WriteLine("Set 单次耗时(ms):" + (dt0 - dt).TotalMilliseconds);
43+
Console.WriteLine("Get 单次耗时(ms):" + (dt1 - dt0).TotalMilliseconds);
44+
45+
var dt2 = SystemTime.Now;
46+
47+
for (var i = 0; i < 1000; i++)
48+
{
49+
_mo.Set(p => p.Name, "Bob" + i);
50+
var resultX = _mo.Get(p => p.Name);
51+
}
52+
Console.WriteLine("1000 次 Set+Get 耗时(ms):" + (SystemTime.DiffTotalMS(dt2)));
53+
54+
_mo.Set(p => p.Name, "Bob");
55+
56+
var dtS3 = SystemTime.Now;
57+
Person person = new Person { Name = "Alice", Age = 30 };
58+
person.Name = "Bob";
59+
var result2 = person.Name;
60+
var dtE3 = SystemTime.Now;
61+
Console.WriteLine("原始方法 单次 Get+Set 耗时(ms):" + (dtE3 - dtS3).TotalMilliseconds);
62+
63+
64+
var dt4 = DateTime.Now;
65+
for (var i = 0; i < 1000; i++)
66+
{
67+
person.Name = "Bob" + i;
68+
var resultX = person.Name;
69+
}
70+
Console.WriteLine("1000 次 原始方法 耗时(ms):" + SystemTime.DiffTotalMS(dt4));
71+
72+
3473
Assert.AreEqual("Alice", result.OldValue);
3574
Assert.AreEqual("Bob", result.NewValue);
75+
Assert.AreEqual("Bob", _person.Name);
3676
Assert.IsTrue(result.IsChanged);
3777
}
3878

@@ -63,9 +103,13 @@ public void GetChanges_AfterSettingProperties_ReturnsChanges()
63103
[TestMethod]
64104
public void Reset_ResetsObjectStateAndClearsChanges()
65105
{
106+
Assert.AreSame(_mo.Object, _person);
107+
66108
_mo.Set(p => p.Name, "Bob");
67109
_mo.Reset();
68110

111+
Assert.AreNotSame(_mo.Object, _person);
112+
69113
var result = _mo.Get(p => p.Name);
70114
Assert.AreEqual("Alice", result.NewValue);
71115
Assert.IsFalse(result.IsChanged);
@@ -122,7 +166,7 @@ public void TakeSnapshot_RestoreSnapshot()
122166
_mo.TakeSnapshot();
123167

124168
Assert.IsTrue(_mo.Get(z => z.Age).HasShapshot);
125-
Assert.AreEqual( 30,_mo.Get(z => z.Age).SnapshotValue);
169+
Assert.AreEqual(30, _mo.Get(z => z.Age).SnapshotValue);
126170

127171
_mo.Set(p => p.Name, "Dave");
128172
var resultBeforeRestore = _mo.Get(p => p.Name);
@@ -140,6 +184,10 @@ public void TakeSnapshot_RestoreSnapshot()
140184
Assert.AreEqual("Charlie", resultAfterRestore.NewValue);
141185
Assert.IsTrue(resultAfterRestore.IsChanged);
142186
Assert.IsFalse(_mo.HasChanges());
187+
188+
//适用对象覆盖
189+
190+
//TODO
143191
}
144192

145193
[TestMethod]
@@ -151,11 +199,15 @@ public void TestRevertChanges()
151199
_mo.Set(x => x.Name, "I'm Jeffrey");
152200
Assert.IsTrue(_mo.HasChanges());
153201
Assert.AreEqual("I'm Jeffrey", _mo.Get(z => z.Name).NewValue);
202+
Assert.AreEqual("I'm Jeffrey", _person.Name);
154203

155204
_mo.RevertChanges();
156205

157206
// Assert
207+
Assert.AreSame(_mo.Object, _person);
208+
158209
Assert.AreEqual("Alice", _mo.Get(z => z.Name).NewValue);
210+
Assert.AreEqual("Alice", _person.Name);
159211
Assert.IsFalse(_mo.HasChanges());
160212
}
161213
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
using Microsoft.VisualStudio.TestTools.UnitTesting;
2+
using Senparc.CO2NET.MagicObject;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
9+
namespace Senparc.CO2NET.MagicObject.Tests
10+
{
11+
[TestClass()]
12+
public class PropertyChangeResultTests
13+
{
14+
private Person _person;
15+
private MO<Person> _mo;
16+
17+
[TestInitialize]
18+
public void Setup()
19+
{
20+
_person = new Person { Name = "Alice", Age = 30 };
21+
_mo = new MO<Person>(_person);
22+
}
23+
24+
[TestMethod()]
25+
public void ToStringTest()
26+
{
27+
Assert.AreEqual("Alice", _mo.Get(z => z.Name).ToString());
28+
29+
_mo.Set(z => z.Name, "Bob");
30+
31+
Assert.AreEqual("Bob", _mo.Get(z => z.Name).NewValue);
32+
Assert.AreEqual("Alice -> Bob", _mo.Get(z => z.Name).ToString());
33+
}
34+
}
35+
}

src/Senparc.CO2NET.MagicObject/MO.cs

Lines changed: 106 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,53 @@
1-
using System;
1+
#region Apache License Version 2.0
2+
/*----------------------------------------------------------------
3+
4+
Copyright 2023 Suzhou Senparc Network Technology Co.,Ltd.
5+
6+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
7+
except in compliance with the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software distributed under the
12+
License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13+
either express or implied. See the License for the specific language governing permissions
14+
and limitations under the License.
15+
16+
Detail: https://github.com/Senparc/Senparc.CO2NET/blob/master/LICENSE
17+
18+
----------------------------------------------------------------*/
19+
#endregion Apache License Version 2.0
20+
21+
/*----------------------------------------------------------------
22+
Copyright (C) 2024 Senparc
23+
24+
文件名:Enums.cs
25+
文件功能描述:枚举配置文件
26+
27+
28+
创建标识:MO - 20240730
29+
30+
修改标识:Senparc - 20240731
31+
修改描述:v0.0.2 将 MO.OriginObject 和 MO.Object 属性设为 public
32+
33+
----------------------------------------------------------------*/
34+
35+
using System;
236
using System.Collections.Generic;
337
using System.Linq.Expressions;
438
using System.Reflection;
539

640
namespace Senparc.CO2NET.MagicObject
741
{
42+
/// <summary>
43+
/// MagicObject 对象
44+
/// </summary>
45+
/// <typeparam name="T"></typeparam>
846
public class MO<T>
47+
//where T:class
948
{
10-
private T OriginalObject { get; set; }
11-
private T Object { get; set; }
49+
public T OriginalObject { get; set; }
50+
public T Object { get; set; }
1251
private Dictionary<string, PropertyChangeResult<object>> _changes;
1352
private T _snapshot;
1453

@@ -21,6 +60,14 @@ public MO(T obj)
2160
_changes = new Dictionary<string, PropertyChangeResult<object>>();
2261
}
2362

63+
/// <summary>
64+
/// 设置属性值
65+
/// </summary>
66+
/// <typeparam name="TValue"></typeparam>
67+
/// <param name="expression">需要设置属性的对象</param>
68+
/// <param name="value">值</param>
69+
/// <returns></returns>
70+
/// <exception cref="ArgumentException"></exception>
2471
public MO<T> Set<TValue>(Expression<Func<T, TValue>> expression, TValue value)
2572
{
2673
MemberExpression memberExpression = null;
@@ -60,7 +107,13 @@ public MO<T> Set<TValue>(Expression<Func<T, TValue>> expression, TValue value)
60107
return this;
61108
}
62109

63-
110+
/// <summary>
111+
/// 获取属性值
112+
/// </summary>
113+
/// <typeparam name="TValue"></typeparam>
114+
/// <param name="expression">需要获取的属性</param>
115+
/// <returns></returns>
116+
/// <exception cref="ArgumentException"></exception>
64117
public PropertyChangeResult<TValue> Get<TValue>(Expression<Func<T, TValue>> expression)
65118
{
66119
if (expression.Body is MemberExpression memberExpression && memberExpression.Member is PropertyInfo propertyInfo)
@@ -87,22 +140,39 @@ public PropertyChangeResult<TValue> Get<TValue>(Expression<Func<T, TValue>> expr
87140
}
88141
}
89142

143+
/// <summary>
144+
/// 获取所有的修改
145+
/// </summary>
146+
/// <returns></returns>
90147
public Dictionary<string, PropertyChangeResult<object>> GetChanges()
91148
{
92149
return _changes;
93150
}
94151

152+
/// <summary>
153+
/// 使用旧对象的副本覆盖当前对象(注意将丢失对原有对象的引用,请慎重使用)
154+
/// <para>如果不希望丢失对原有对象的引用,请使用 <see cref="RevertChanges"/> 方法</para>
155+
/// </summary>
95156
public void Reset()
96157
{
97158
Object = Clone(OriginalObject);
98159
_changes.Clear();
99160
}
100161

162+
/// <summary>
163+
/// 检查是否具有修改
164+
/// </summary>
165+
/// <returns></returns>
101166
public bool HasChanges()
102167
{
103168
return _changes.Count > 0;
104169
}
105170

171+
/// <summary>
172+
/// 批量设置属性值
173+
/// </summary>
174+
/// <param name="properties"></param>
175+
/// <exception cref="ArgumentException"></exception>
106176
public void SetProperties(Dictionary<Expression<Func<T, object>>, object> properties)
107177
{
108178
foreach (var property in properties)
@@ -123,40 +193,65 @@ public void SetProperties(Dictionary<Expression<Func<T, object>>, object> proper
123193
}
124194

125195

126-
196+
/// <summary>
197+
/// 获取快照
198+
/// </summary>
127199
public void TakeSnapshot()
128200
{
129201
_snapshot = Clone(Object);
130202
}
131203

132-
public void RestoreSnapshot()
204+
/// <summary>
205+
/// 将快照还原到对象
206+
/// </summary>
207+
/// <param name="keepObjectInstance">是否保持当前对象引用,如果为否,将使用 Clone 的旧对象</param>
208+
public void RestoreSnapshot(bool keepObjectInstance = true)
133209
{
134210
if (_snapshot != null)
135211
{
136-
Object = Clone(_snapshot);
212+
if (keepObjectInstance)
213+
{
214+
RevertProperties(Object, _snapshot);
215+
}
216+
else
217+
{
218+
Object = Clone(_snapshot);
219+
}
137220
_changes.Clear();
138221
}
139222
}
140223

224+
/// <summary>
225+
/// 克隆对象
226+
/// </summary>
227+
/// <param name="source"></param>
228+
/// <returns></returns>
141229
private T Clone(T source)
142230
{
143231
var cloneMethod = source.GetType().GetMethod("MemberwiseClone", BindingFlags.Instance | BindingFlags.NonPublic);
144232
return (T)cloneMethod.Invoke(source, null);
145233
}
146234

147-
public void RevertChanges()
235+
private void RevertProperties(T target,T originalObject)
148236
{
149-
var properties = OriginalObject.GetType().GetProperties();
237+
var properties = typeof(T).GetProperties();
150238
foreach (var property in properties)
151239
{
152240
if (property.CanWrite)
153241
{
154-
var originalValue = property.GetValue(OriginalObject);
242+
var originalValue = property.GetValue(originalObject);
155243
property.SetValue(Object, originalValue);
156244
}
157245
}
158-
_changes.Clear();
159246
}
160247

248+
/// <summary>
249+
/// 在当前引用对象基础上,还原所有修改(不会改变引用对象)
250+
/// </summary>
251+
public void RevertChanges()
252+
{
253+
RevertProperties(Object, OriginalObject);
254+
_changes.Clear();
255+
}
161256
}
162257
}

0 commit comments

Comments
 (0)