Skip to content

Commit

Permalink
Improve performance and change inner property behavior
Browse files Browse the repository at this point in the history
  • Loading branch information
ApmeM committed Jul 20, 2023
1 parent bb5d12f commit ce768b9
Show file tree
Hide file tree
Showing 17 changed files with 215 additions and 133 deletions.
25 changes: 10 additions & 15 deletions ReflectionUtilities.Benchmarks/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using BenchmarkDotNet.Running;
using ReflectionUtilities;
using System.Collections.Generic;
using System.Linq;
using System;

[MemoryDiagnoser]
Expand All @@ -27,25 +26,21 @@ public static void Main(string[] args)
BenchmarkRunner.Run<Program>();
}

private ExampleObject obj = new ExampleObject();

[Benchmark]
public void UseReflectionCache()
public void GetAndUseProperty_WithCache()
{
var type = ReflectionCache.GetReflection(typeof(ExampleObject));
var property = type.Properties["Property2"];
ExampleObject obj = new ExampleObject();
property.SetValue(obj, "test string");
var value = property.GetValue(obj);
var attributes = property.Attributes;
var reflectionType = ReflectionCache.GetReflection(typeof(ExampleObject));
var property = reflectionType.Properties["Property2"];
property.SetValue(obj, "test");
}

[Benchmark]
public void RegularReflection()
public void GetAndUseProperty_Reflection()
{
var type = typeof(ExampleObject);
var property = type.GetProperties().Where(a => a.Name == "Property2").Single();
ExampleObject obj = new ExampleObject();
property.SetValue(obj, "test string");
property.GetValue(obj);
property.GetCustomAttributes(true);
var objType = typeof(ExampleObject);
var property = objType.GetProperty("Property2");
property.SetValue(obj, "test");
}
}
6 changes: 4 additions & 2 deletions ReflectionUtilities.Test/ExampleObjects/ExampleObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ public class ExampleObject : IExampleInterface
[Custom]
public int Field2;

public int Property1 { get; set; }
public string Property1 { get; set; }

int IExampleInterface.Property1 { get; set; }

[Custom]
[Custom]
Expand Down Expand Up @@ -48,7 +50,7 @@ public void Test()

[Custom]
[Custom]
public void Test(int value)
public void Test(string value)
{
this.Property1 = value;
}
Expand Down
39 changes: 0 additions & 39 deletions ReflectionUtilities.Test/ReflectionClassTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,45 +8,6 @@
[TestFixture]
public class ReflectionClassTest
{
[Test]
public void Attributes_AttributesExist_Count()
{
// Arrange
var reflection = ReflectionCache.GetReflection(typeof(ExampleObject));

// Act
int count = reflection.Attributes.Count;

// Assert
Assert.AreEqual(4, count);
}

[Test]
public void Properties_PropertiesExist_Count()
{
// Arrange
var reflection = ReflectionCache.GetReflection(typeof(ExampleObject));

// Act
int count = reflection.Properties.Count;

// Assert
Assert.AreEqual(4, count);
}

[Test]
public void Methods_MethodsExist_CountWithStandart()
{
// Arrange
var reflection = ReflectionCache.GetReflection(typeof(ExampleObject));

// Act
int count = reflection.Methods.Count;

// Assert
Assert.AreEqual(7, count);
}

[Test]
public void BaseType_AnyObject_RealObjectType()
{
Expand Down
2 changes: 1 addition & 1 deletion ReflectionUtilities.Test/ReflectionMethodListTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public void GetMethodList_MethodCount_WithoutPropertiesWithStandart()
int count = rc.Methods.Count;

// Assert
Assert.AreEqual(7, count);
Assert.AreEqual(7 + 3*2, count);
}

[Test]
Expand Down
4 changes: 2 additions & 2 deletions ReflectionUtilities.Test/ReflectionMethodTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,10 @@ public void Invoke_ValidObject_ValidValue()
ExampleObject obj = new ExampleObject();

// Act
reflection.Invoke(obj, 3);
reflection.Invoke(obj, "3");

// Assert
Assert.AreEqual(3, obj.Property1);
Assert.AreEqual("3", obj.Property1);
}
}
}
4 changes: 2 additions & 2 deletions ReflectionUtilities.Test/ReflectionPropertyListTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,10 @@ public void FindPropertyByName_PropertyNotExist_Null()
ReflectionClass rc = ReflectionCache.GetReflection(typeof(ExampleObject));

// Act
var property = rc.Properties["Property12"];
var propertyExists = rc.Properties.ContainsKey("Property12");

// Assert
Assert.IsNull(property);
Assert.IsFalse(propertyExists);
}
}
}
7 changes: 4 additions & 3 deletions ReflectionUtilities.Test/ReflectionPropertyTest.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
namespace ReflectionUtilities.Test
{
using System;
using System.Linq;
using System.Reflection;
using NUnit.Framework;

Expand Down Expand Up @@ -85,7 +86,7 @@ public void PropertyType_PropertyExist_PropertyType()
var propertyType = reflection.PropertyType;

// Assert
Assert.AreEqual(typeof(ExampleObject), propertyType);
Assert.AreEqual(typeof(ExampleObject), propertyType.BaseType);
}

[Test]
Expand Down Expand Up @@ -133,7 +134,7 @@ public void GetValue_NoSetter_NoSuchMethodException()

// Act
// Assert
Assert.Throws<NullReferenceException>(() => reflection.GetValue(obj));
Assert.Throws<ArgumentException>(() => reflection.GetValue(obj));
}

[Test]
Expand Down Expand Up @@ -181,7 +182,7 @@ public void SetValue_NoSetter_NoSuchMethodException()

// Act
// Assert
Assert.Throws<NullReferenceException>(() => reflection.SetValue(obj, "test string"));
Assert.Throws<ArgumentException>(() => reflection.SetValue(obj, "test string"));
}
}
}
7 changes: 5 additions & 2 deletions ReflectionUtilities/ReflectionAttributeList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@

public class ReflectionAttributeList : List<Attribute>
{
internal ReflectionAttributeList(List<Attribute> attributes)
internal ReflectionAttributeList(object[] attributes)
{
this.AddRange(attributes);
foreach (var attr in attributes)
{
this.Add((Attribute)attr);
}
}

public List<Attribute> this[Type type] => this.Where(a => a.GetType() == type).ToList();
Expand Down
109 changes: 92 additions & 17 deletions ReflectionUtilities/ReflectionClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,104 @@

public class ReflectionClass
{
private readonly Dictionary<(Type, Type), bool> isAssignableFromCache = new Dictionary<(Type, Type), bool>();
private Dictionary<(Type, Type), bool> isAssignableFromCache = new Dictionary<(Type, Type), bool>();
private ReflectionAttributeList attributes;
private string fullName;
private string name;
private ReflectionFieldList fields;
private ReflectionConstructorList constructors;
private ReflectionPropertyList properties;
private ReflectionMethodList methods;

public ReflectionAttributeList Attributes { get; }
public Type BaseType { get; }
public string FullName { get; }
public ReflectionMethodList Methods { get; }
public string Name { get; }
public ReflectionPropertyList Properties { get; }
public ReflectionFieldList Fields { get; }
public ReflectionConstructorList Constructors { get; }
public string FullName
{
get
{
if (this.fullName == null)
{
this.fullName = BaseType.FullName;
}
return this.fullName;
}
}

public string Name
{
get
{
if (this.name == null)
{
this.name = BaseType.Name;
}
return this.name;
}
}

public ReflectionAttributeList Attributes
{
get
{
if (this.attributes == null)
{
this.attributes = new ReflectionAttributeList(BaseType.GetCustomAttributes(true));
}
return this.attributes;
}
}

// It includes also property get and set methods.
public ReflectionMethodList Methods
{
get
{
if (this.methods == null)
{
this.methods = new ReflectionMethodList(this.BaseType.GetMethods(), this);
}
return this.methods;
}
}

public ReflectionPropertyList Properties
{
get
{
if (this.properties == null)
{
this.properties = new ReflectionPropertyList(this.BaseType.GetProperties(), this);
}
return this.properties;
}
}

public ReflectionFieldList Fields
{
get
{
if (this.fields == null)
{
this.fields = new ReflectionFieldList(this.BaseType.GetFields(), this);
}
return this.fields;
}
}

public ReflectionConstructorList Constructors
{
get
{
if (this.constructors == null)
{
this.constructors = new ReflectionConstructorList(this.BaseType.GetConstructors(), this);
}
return this.constructors;
}
}

internal ReflectionClass(Type type)
{
this.Attributes = new ReflectionAttributeList(type.GetCustomAttributes(true).OfType<Attribute>().ToList());
this.BaseType = type;
var propertyInfos = type.GetProperties().ToList();
var propertyMethods = propertyInfos.SelectMany(a => new[] { a.GetGetMethod(), a.GetSetMethod() });
this.Properties = new ReflectionPropertyList(propertyInfos, this);
this.Methods = new ReflectionMethodList(type.GetMethods().Except(propertyMethods).ToList(), this);
this.Fields = new ReflectionFieldList(type.GetFields().ToList(), this);
this.Constructors = new ReflectionConstructorList(type.GetConstructors().ToList(), this);
this.Name = type.Name;
this.FullName = type.FullName;
}

public bool IsAssignableFrom(Type type)
Expand Down
5 changes: 1 addition & 4 deletions ReflectionUtilities/ReflectionConstructor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,11 @@ internal ReflectionConstructor(ConstructorInfo method, ReflectionClass parent)
this.constructor = method;
this.Parent = parent;

// this.returnType = this.constructor..ReturnType;
this.Attributes =
new ReflectionAttributeList(this.constructor.GetCustomAttributes(true).OfType<Attribute>().ToList());
this.Attributes = new ReflectionAttributeList(this.constructor.GetCustomAttributes(true));
this.Name = this.constructor.Name;
this.Parameters = this.constructor.GetParameters();
}


public object Invoke(params object[] param)
{
return this.constructor.Invoke(param);
Expand Down
2 changes: 1 addition & 1 deletion ReflectionUtilities/ReflectionConstructorList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ReflectionUtilities
{
public class ReflectionConstructorList : List<ReflectionConstructor>
{
internal ReflectionConstructorList(List<ConstructorInfo> contructors, ReflectionClass parent)
internal ReflectionConstructorList(ConstructorInfo[] contructors, ReflectionClass parent)
{
this.AddRange(contructors.Select(a => new ReflectionConstructor(a, parent)));
}
Expand Down
3 changes: 1 addition & 2 deletions ReflectionUtilities/ReflectionField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ internal ReflectionField(FieldInfo field, ReflectionClass parent)
this.field = field;
this.Parent = parent;

this.Attributes =
new ReflectionAttributeList(this.field.GetCustomAttributes(true).OfType<Attribute>().ToList());
this.Attributes = new ReflectionAttributeList(this.field.GetCustomAttributes(true));
this.Name = this.field.Name;
this.FieldType = this.field.FieldType;

Expand Down
2 changes: 1 addition & 1 deletion ReflectionUtilities/ReflectionFieldList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ namespace ReflectionUtilities
{
public class ReflectionFieldList : List<ReflectionField>
{
internal ReflectionFieldList(List<FieldInfo> fields, ReflectionClass parent)
internal ReflectionFieldList(FieldInfo[] fields, ReflectionClass parent)
{
this.AddRange(fields.Select(a => new ReflectionField(a, parent)));
}
Expand Down
15 changes: 7 additions & 8 deletions ReflectionUtilities/ReflectionMethod.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

public class ReflectionMethod
{
private readonly MethodInfo method;
public MethodInfo BaseMethod { get; }

public string Name { get; }
public ParameterInfo[] Parameters { get; }
Expand All @@ -19,19 +19,18 @@ public class ReflectionMethod

internal ReflectionMethod(MethodInfo method, ReflectionClass parent)
{
this.method = method;
this.BaseMethod = method;
this.Parent = parent;

this.ReturnType = this.method.ReturnType;
this.Attributes =
new ReflectionAttributeList(this.method.GetCustomAttributes(true).OfType<Attribute>().ToList());
this.Name = this.method.Name;
this.Parameters = this.method.GetParameters();
this.ReturnType = this.BaseMethod.ReturnType;
this.Attributes = new ReflectionAttributeList(this.BaseMethod.GetCustomAttributes(true));
this.Name = this.BaseMethod.Name;
this.Parameters = this.BaseMethod.GetParameters();
}

public object Invoke(object obj, params object[] param)
{
return this.method.Invoke(obj, param);
return this.BaseMethod.Invoke(obj, param);
}
}
}
Loading

0 comments on commit ce768b9

Please sign in to comment.