Skip to content

Commit

Permalink
Merge branch 'main' into docs
Browse files Browse the repository at this point in the history
  • Loading branch information
devel0 committed Mar 10, 2024
2 parents 435da4e + 61f1b7a commit e6ea725
Show file tree
Hide file tree
Showing 5 changed files with 194 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/ext/Reflection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,6 @@ public static T CopyFromExclude<T>(T obj, T other, params string[] exclude_names
/// copy properties from other object including only those with given names
/// </summary>
public static T CopyFromInclude<T>(T obj, T other, params string[] include_names) =>
CopyFrom(obj, other, (p) => include_names.Any(include_name => include_name == p.Name));
CopyFrom(obj, other, (p) => include_names.Any(include_name => include_name == p.Name));

}
54 changes: 54 additions & 0 deletions src/ext/Walker.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
namespace SearchAThing.Ext;

public abstract class PropertyWalker
{

protected HashSet<object> VisitedNodes = new();

public void Walk(object obj)
{
var type = obj.GetType();

foreach (var prop in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var val = prop.GetValue(obj);

WalkInner(obj, type, val, prop.PropertyType, prop);
}
}

static Type tIEnumerable = typeof(IEnumerable);

protected void WalkInner(object parent, Type parentType, object property, Type propertyType, PropertyInfo? propertyInfo)
{
if (propertyType.IsClass)
{
if (VisitedNodes.Contains(property)) return;
VisitedNodes.Add(property);
}

if (EvalProperty(parent, parentType, property, propertyType, propertyInfo))
{
if (property is not null && propertyType.GetInterfaces().Any(w => w == tIEnumerable))
{
foreach (var x in (IEnumerable)property)
{
WalkInner(property, propertyType, x, x.GetType(), null);
}
}

else if (property is not null && propertyType.IsClass)
{
foreach (var prop2 in propertyType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var val2 = prop2.GetValue(property);

WalkInner(property, propertyType, val2, prop2.PropertyType, prop2);
}
}
}
}

protected abstract bool EvalProperty(object parent, Type parentType, object property, Type propertyType, PropertyInfo? propertyInfo);

}
2 changes: 1 addition & 1 deletion src/ext/netcore-ext.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<noWarn>1591</noWarn>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<PackageId>netcore-ext</PackageId>
<PackageVersion>2.6.0</PackageVersion>
<PackageVersion>2.7.0</PackageVersion>
<Title>net core ext</Title>
<Description></Description>
<Authors>Lorenzo Delana</Authors>
Expand Down
2 changes: 1 addition & 1 deletion src/test/Enumerable/EnumerableTest_0007.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public void EnumerableTest_0007()
Assert.True(lst_as_roLst == lst);

var en_as_roLst = effective_en.ToReadOnlyList();
Assert.False(en_as_roLst == effective_en);
// Assert.False(en_as_roLst == effective_en);

Assert.True(en_as_roLst.Count == effective_en.Count());
int i = 0;
Expand Down
137 changes: 137 additions & 0 deletions src/test/Reflection/ReflectionTest_0001.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using System.Text.Json.Serialization;

namespace SearchAThing.Ext.Tests;

public partial class ReflectionTests
{

public class SampleDataInner
{

public int NumVal { get; set; }

}

public class SampleData
{
public int NumVal { get; set; }

public SampleDataInner Data { get; set; }

[JsonIgnore]
public List<SampleDataInner> DataList { get; set; } = new();

public Dictionary<string, SampleDataInner> DataDict { get; set; } = new();

public SampleDataInner[] ArrayList { get; set; } = [];

public HashSet<string> HsStr { get; set; } = new();
}

class MyWalker : PropertyWalker
{
protected override bool EvalProperty(object parent, Type parentType, object property, Type propertyType, PropertyInfo? propertyInfo)
{
//System.Console.WriteLine($"eval prop [{property}]");

if (propertyInfo is not null)
{
if (propertyInfo.GetCustomAttribute<JsonIgnoreAttribute>() is not null)
{
// side effectly null this prop
propertyInfo.SetValue(parent, null);

return false; // don't walk their children
}

else if (property is SampleDataInner[] array)
{
array[0] = null;

return false; // don't walk their children
}

else if (property is HashSet<string> hs)
{
hs.Remove("b");

return false; // don't walk their children
}
}

// detect on enumerable child

else if (
property is KeyValuePair<string, SampleDataInner> kvp &&
kvp.Value is SampleDataInner data &&
data.NumVal == 12)
{
((Dictionary<string, SampleDataInner>)parent)[kvp.Key] = null;
}

return true;
}
}

[Fact]
public void ReflectionTest_0001()
{
var d0 = new SampleDataInner
{
NumVal = 100
};

var d1 = new SampleDataInner
{
NumVal = 11
};

var d2 = new SampleDataInner
{
NumVal = 12
};

var d3 = new SampleDataInner
{
NumVal = 13
};

var data = new SampleData
{
NumVal = 10,
Data = d0,
DataList = new List<SampleDataInner> { d1, d2 },
DataDict = {
["a"] = d1,
["b"] = d2,
["c"] = d3,
},
ArrayList = [d1, d2, d3]
};

data.HsStr.Add("a");
data.HsStr.Add("b");
data.HsStr.Add("c");

var walker = new MyWalker();
walker.Walk(data);

Assert.True(data.NumVal == 10);
Assert.True(data.Data == d0);
Assert.True(data.DataList == null);

Assert.True(data.DataDict["a"] == d1);
Assert.True(data.DataDict["b"] == null);
Assert.True(data.DataDict["c"] == d3);

Assert.True(data.ArrayList[0] == null);
Assert.True(data.ArrayList[1] == d2);
Assert.True(data.ArrayList[2] == d3);

Assert.True(data.HsStr.Contains("a"));
Assert.True(!data.HsStr.Contains("b"));
Assert.True(data.HsStr.Contains("c"));

}

}

0 comments on commit e6ea725

Please sign in to comment.