Skip to content

Commit 3075aa9

Browse files
authored
Merge pull request #143 from NerosoftDev/develop
Develop
2 parents 03b6ef6 + ef459c9 commit 3075aa9

8 files changed

Lines changed: 117 additions & 29 deletions

File tree

Source/Euonia.Domain/Commands/Command.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
using System.ComponentModel;
2-
using Nerosoft.Euonia.Reflection;
1+
using Nerosoft.Euonia.Reflection;
32

43
namespace Nerosoft.Euonia.Domain;
54

Source/Euonia.Osba/Abstracts/IBusinessObject.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@ public interface IBusinessObject : IUseBusinessContext, INotifyPropertyChanged,
4545
/// <returns>The value of the specified property, or null if the property has not been set.</returns>
4646
object ReadProperty(IPropertyInfo propertyInfo);
4747

48+
/// <summary>
49+
/// Retrieves the value of the property specified by its name.
50+
/// </summary>
51+
/// <remarks>
52+
/// Use this method to access the current value of a property identified by its name.
53+
/// Ensure that the property name provided corresponds to a valid property that can be read. This method does not set or modify the property value.
54+
/// </remarks>
55+
/// <param name="propertyName">The name of the property to read. Must represent a readable property.</param>
56+
/// <returns>The value of the specified property, or null if the property has not been set.</returns>
57+
object ReadProperty(string propertyName);
58+
4859
/// <summary>
4960
/// Reads the value of the specified property and returns it as the requested type.
5061
/// </summary>
@@ -58,6 +69,18 @@ public interface IBusinessObject : IUseBusinessContext, INotifyPropertyChanged,
5869
/// null.</param>
5970
/// <returns>The value of the specified property, cast to the type specified by <typeparamref name="TValue"/>.</returns>
6071
TValue ReadProperty<TValue>(PropertyInfo<TValue> propertyInfo);
72+
73+
/// <summary>
74+
/// Reads the value of the specified property by its name and returns it as the requested type.
75+
/// </summary>
76+
/// <remarks>
77+
/// Ensure that the property name provided corresponds to a valid property that can be read and that the value can be cast to <typeparamref name="TValue"/>.
78+
/// An exception may be thrown if the property is not readable or if the value cannot be cast to the specified type.
79+
/// </remarks>
80+
/// <param name="propertyName">The name of the property to read. Must represent a readable property.</param>
81+
/// <typeparam name="TValue">The type of the property value to be read.</typeparam>
82+
/// <returns>The value of the specified property, cast to the type specified by <typeparamref name="TValue"/>.</returns>
83+
TValue ReadProperty<TValue>(string propertyName);
6184

6285
/// <summary>
6386
/// Loads the specified property with a new value, updating the property's value according to its metadata information.

Source/Euonia.Osba/Core/BusinessObject.cs

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ protected void PropertyHasChanged(string propertyName)
351351
protected internal sealed class BypassRuleChecksObject : IDisposable
352352
{
353353
private BusinessObject _target;
354-
private static readonly object _lock = new();
354+
private static readonly Lock _lock = new();
355355

356356
private BypassRuleChecksObject(BusinessObject target)
357357
{
@@ -416,12 +416,14 @@ private void DeRef()
416416
lock (_lock)
417417
{
418418
_refCount -= 1;
419-
if (_refCount == 0)
419+
if (_refCount != 0)
420420
{
421-
_target.IsBypassingRuleChecks = false;
422-
_target.InternalBypassRuleChecks = null;
423-
_target = null;
421+
return;
424422
}
423+
424+
_target.IsBypassingRuleChecks = false;
425+
_target.InternalBypassRuleChecks = null;
426+
_target = null;
425427
}
426428
}
427429

@@ -508,6 +510,52 @@ public virtual object ReadProperty(IPropertyInfo propertyInfo)
508510
return result;
509511
}
510512

513+
/// <summary>
514+
/// Gets a property's value by property name.
515+
/// </summary>
516+
/// <param name="propertyName"></param>
517+
/// <returns></returns>
518+
/// <exception cref="InvalidOperationException"></exception>
519+
public virtual object ReadProperty(string propertyName)
520+
{
521+
var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
522+
if (propertyInfo == null)
523+
{
524+
throw new InvalidOperationException($"Property {propertyName} is not registered.");
525+
}
526+
527+
return ReadProperty(propertyInfo);
528+
}
529+
530+
/// <summary>
531+
/// Reads the value of the specified property by its name and returns it as the requested type.
532+
/// </summary>
533+
/// <param name="propertyName">The name of the property to read. Must represent a readable property.</param>
534+
/// <typeparam name="TValue">The type of the property value to be read.</typeparam>
535+
/// <returns>The value of the specified property, cast to the type specified by <typeparamref name="TValue"/>.</returns>
536+
/// <exception cref="InvalidOperationException">
537+
/// Thrown if the property name provided does not correspond to a valid property that can be read, or if the value cannot be cast to the specified type.
538+
/// </exception>
539+
public virtual TValue ReadProperty<TValue>(string propertyName)
540+
{
541+
var propertyInfo = FieldManager.GetRegisteredProperty(propertyName);
542+
543+
if (propertyInfo == null)
544+
{
545+
throw new InvalidOperationException($"Property {propertyName} is not registered.");
546+
}
547+
548+
if (propertyInfo is not PropertyInfo<TValue> property)
549+
{
550+
throw new InvalidOperationException("The property type does not match the expected type.");
551+
}
552+
553+
{
554+
}
555+
556+
return ReadProperty(property);
557+
}
558+
511559
#endregion
512560

513561
#region Load Properties

Source/Euonia.Osba/Core/ObservableList.cs

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
1-
using System;
2-
using System.Collections.Generic;
3-
using System.Collections.ObjectModel;
1+
using System.Collections.ObjectModel;
42
using System.Collections.Specialized;
53
using System.ComponentModel;
6-
using System.Linq;
7-
using System.Text;
8-
using System.Threading.Tasks;
94

105
namespace Nerosoft.Euonia.Osba;
116

@@ -21,8 +16,8 @@ namespace Nerosoft.Euonia.Osba;
2116
/// can suppress change notifications during batch updates to improve performance and avoid unnecessary UI refreshes. It
2217
/// also propagates property and busy state changes from child items, enabling more granular change tracking.
2318
/// </remarks>
24-
/// <typeparam name="T">The type of elements contained in the observable list.</typeparam>
25-
public class ObservableList<T> : ObservableCollection<T>, INotifyBusy
19+
/// <typeparam name="TItem">The type of elements contained in the observable list.</typeparam>
20+
public class ObservableList<TItem> : ObservableCollection<TItem>, INotifyBusy
2621
{
2722
private EventHandler<ObjectChangedEventArgs> _childChanged = null;
2823

@@ -50,7 +45,8 @@ public event EventHandler<ObjectChangedEventArgs> ChildChanged
5045
public bool RaiseListChangedEvents { get; set; } = true;
5146

5247
#region BusyChanged
53-
private BusyChangedEventHandler _busyChanged = null;
48+
49+
private BusyChangedEventHandler _busyChanged;
5450

5551
/// <summary>
5652
/// Event indicating that the busy status of the
@@ -96,6 +92,7 @@ protected void OnBusyChanged(string propertyName, bool busy)
9692
/// <remarks>This property reflects the state of the IsBusy property, providing a convenient way to check if the
9793
/// instance is currently engaged in operations.</remarks>
9894
public virtual bool IsSelfBusy => IsBusy;
95+
9996
#endregion
10097

10198
/// <summary>
@@ -117,7 +114,7 @@ protected override void RemoveItem(int index)
117114
/// after insertion. This allows the collection to respond to events raised by the item.</remarks>
118115
/// <param name="index">The zero-based index at which the item should be inserted into the collection.</param>
119116
/// <param name="item">The item to insert and attach event hooks to.</param>
120-
protected override void InsertItem(int index, T item)
117+
protected override void InsertItem(int index, TItem item)
121118
{
122119
base.InsertItem(index, item);
123120
AddEventHooks(item);
@@ -142,7 +139,7 @@ protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
142139
/// Removes event hooks from an item.
143140
/// </summary>
144141
/// <param name="item"></param>
145-
protected virtual void RemoveEventHooks(T item)
142+
protected virtual void RemoveEventHooks(TItem item)
146143
{
147144
if (item == null)
148145
{
@@ -167,7 +164,7 @@ protected virtual void RemoveEventHooks(T item)
167164
/// PropertyChanged event if the item implements INotifyPropertyChanged. These subscriptions enable the system to
168165
/// respond to changes in the item's state or properties.</remarks>
169166
/// <param name="item">The item to which event handlers are added. This parameter must not be null; if null, no handlers are attached.</param>
170-
protected virtual void AddEventHooks(T item)
167+
protected virtual void AddEventHooks(TItem item)
171168
{
172169
if (item == null)
173170
{
@@ -203,6 +200,7 @@ protected virtual void OnChildChanged(ObjectChangedEventArgs args)
203200
}
204201

205202
#region Event Subscriptions
203+
206204
private void OnItemBusyChanged(object sender, BusyChangedEventArgs e)
207205
{
208206
OnBusyChanged(e);
@@ -212,13 +210,14 @@ private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
212210
{
213211
RaiseChildChanged(sender, e, null);
214212
}
213+
215214
#endregion
216215

217216
/// <summary>
218217
/// Use this object to suppress ListChangedEvents for an entire code block.
219218
/// May be nested in multiple levels for the same object.
220219
/// </summary>
221-
public IDisposable SuppressListChangedEvents => new SuppressListChangedEventsClass<T>(this);
220+
public IDisposable SuppressListChangedEvents => new SuppressListChangedEventsClass<TItem>(this);
222221

223222
/// <summary>
224223
/// <![CDATA[Provides a mechanism to temporarily suppress change notifications for an ObservableList<T> instance.]]>
@@ -230,13 +229,13 @@ private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs e)
230229
/// improving performance and avoiding unnecessary updates to data-bound controls during batch operations.
231230
/// ]]>
232231
/// </remarks>
233-
/// <typeparam name="D">The type of elements contained in the observable list.</typeparam>
234-
private class SuppressListChangedEventsClass<D> : IDisposable
232+
/// <typeparam name="TList">The type of elements contained in the observable list.</typeparam>
233+
private class SuppressListChangedEventsClass<TList> : IDisposable
235234
{
236-
private readonly ObservableList<D> _listObject;
235+
private readonly ObservableList<TList> _listObject;
237236
private readonly bool _initialRaiseListChangedEvents;
238237

239-
public SuppressListChangedEventsClass(ObservableList<D> listObject)
238+
public SuppressListChangedEventsClass(ObservableList<TList> listObject)
240239
{
241240
_listObject = listObject;
242241
_initialRaiseListChangedEvents = listObject.RaiseListChangedEvents;

Source/Euonia.Osba/Factory/ObjectReflector.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,9 @@ private static MethodInfo FindMatchedMethod<TTarget>(Type attributeType, object[
194194
public static MethodInfo FindMatchedMethod<TTarget>(Type attributeType, IReadOnlyList<Type> parameterTypes)
195195
{
196196
var methods = typeof(TTarget).GetRuntimeMethods()
197-
.Where(t => t.GetCustomAttribute(attributeType) != null);
198-
if (methods == null || !methods.Any())
197+
.Where(t => t.GetCustomAttribute(attributeType) != null)
198+
.ToList();
199+
if (methods is not { Count: > 0 })
199200
{
200201
throw new MissingMethodException($"Missing method with attribute '{attributeType.Name}' on {typeof(TTarget).FullName}");
201202
}

Source/Euonia.Osba/Reflection/FieldDataManager.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,24 @@ public IFieldData GetFieldData(IPropertyInfo property)
103103
}
104104
}
105105

106+
/// <summary>
107+
/// Gets the field data for a property with specified name.
108+
/// </summary>
109+
/// <param name="propertyName"></param>
110+
/// <returns></returns>
111+
/// <exception cref="InvalidOperationException"></exception>
112+
public IFieldData GetFieldData(string propertyName)
113+
{
114+
try
115+
{
116+
return _fieldData.GetValueOrDefault(propertyName);
117+
}
118+
catch (IndexOutOfRangeException ex)
119+
{
120+
throw new InvalidOperationException(RESOURCE_PROPERTY_NAME_NOT_REGISTERED, ex);
121+
}
122+
}
123+
106124
private IFieldData GetOrCreateFieldData(IPropertyInfo property)
107125
{
108126
try

Source/Euonia.Validation/Core/Validator.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ public class Validator
1414
public static void Validate<T>(T item)
1515
where T : class
1616
{
17-
ArgumentAssert.ThrowIfNull(item, nameof(item));
17+
ArgumentAssert.ThrowIfNull(item);
1818

1919
if (item is IValidatableObject @object)
2020
{
@@ -42,7 +42,7 @@ public static void Validate<T>(T item)
4242
public static async Task ValidateAsync<T>(T item)
4343
where T : class
4444
{
45-
ArgumentAssert.ThrowIfNull(item, nameof(item));
45+
ArgumentAssert.ThrowIfNull(item);
4646

4747
if (item is IValidatableObject @object)
4848
{

project.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>10.4.1</Version>
3+
<Version>10.4.2</Version>
44
<Authors>damon</Authors>
55
<Company>Nerosoft Ltd.</Company>
66
<Product>Euonia</Product>

0 commit comments

Comments
 (0)