PropertyAccessor Class

Provides an efficient way for setting and getting property values via dynamically created delegates.

Definition

Namespace: KGySoft.Reflection
Assembly: KGySoft.CoreLibraries (in KGySoft.CoreLibraries.dll) Version: 9.0.0-preview.1
C#
public abstract class PropertyAccessor : MemberAccessor
Inheritance
Object    MemberAccessor    PropertyAccessor

Remarks

You can obtain a PropertyAccessor instance by the static GetAccessor method.

The Get(Object, Object) and Set(Object, Object, Object) methods can be used to get or set the property in general cases. These methods can be used for any properties, including indexed ones.

The other non-generic Get and Set overloads can be used for simple properties or for indexers with one index parameter.

If you know the property type at compile time, then you can use the generic GetStaticValue/SetStaticValue methods for static properties. If you know also the instance type (and the index parameter for indexers), then the GetInstanceValue/SetInstanceValue methods can be used to access instance properties with better performance. These generic methods can be used for properties with no more than one index parameter.

The first call of these methods are slower because the delegates are generated on the first access, but further calls are much faster.

The already obtained accessors are cached so subsequent GetAccessor calls return the already created accessors unless they were dropped out from the cache, which can store about 8000 elements.

  Note

If you want to access a property by name rather than by a PropertyInfo, then you can use the SetProperty and GetProperty methods in the Reflector class, which have some overloads with a propertyName parameter.

  Caution

The getter/setter methods of this class in the .NET Standard 2.0 version throw a PlatformNotSupportedException for ref properties. You need to reference the .NET Standard 2.1 build or any .NET Framework or .NET Core/.NET builds to support ref properties.

Example

The following example compares the PropertyAccessor class with PropertyInfo on .NET 8 and .NET Framework 4.8 platforms.
C#
using System;
using System.Reflection;
using System.Runtime.Versioning;

using KGySoft.Diagnostics;
using KGySoft.Reflection;

class Example
{
    private class TestClass
    {
        public int TestProperty { get; set; }
    }

    private static string PlatformName => ((TargetFrameworkAttribute)Attribute.GetCustomAttribute(Assembly.GetExecutingAssembly(),
        typeof(TargetFrameworkAttribute))).FrameworkDisplayName;

    static void Main(string[] args)
    {
        var instance = new TestClass();
        PropertyInfo property = instance.GetType().GetProperty(nameof(TestClass.TestProperty));
        PropertyAccessor accessor = PropertyAccessor.GetAccessor(property);

        new PerformanceTest { TestName = $"Set Property - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => instance.TestProperty = 1, "Direct set")
            .AddCase(() => property.SetValue(instance, 1), "System.Reflection.PropertyInfo.SetValue")
            .AddCase(() => accessor.Set(instance, 1), "PropertyAccessor.Set")
            .AddCase(() => accessor.SetInstanceValue(instance, 1), "PropertyAccessor.SetInstanceValue<,>")
            .DoTest()
            .DumpResults(Console.Out);

        new PerformanceTest<int> { TestName = $"Get Property - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => instance.TestProperty, "Direct get")
            .AddCase(() => (int)property.GetValue(instance), "System.Reflection.PropertyInfo.GetValue")
            .AddCase(() => (int)accessor.Get(instance), "PropertyAccessor.Get")
            .AddCase(() => accessor.GetInstanceValue<TestClass, int>(instance), "PropertyAccessor.GetInstanceValue<,>")
            .DoTest()
            .DumpResults(Console.Out);
    }
}

// This code example produces a similar output to these ones:

// ==[Set Property - .NET 8.0 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 4
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct set: average time: 3.02 ms
// 2. PropertyAccessor.SetInstanceValue<,>: average time: 4.70 ms (+1.67 ms / 155.43%)
// 3. PropertyAccessor.Set: average time: 11.60 ms (+8.58 ms / 384.08%)
// 4. System.Reflection.PropertyInfo.SetValue: average time: 25.79 ms (+22.77 ms / 853.68%)
// 
// ==[Get Property - .NET 8.0 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 4
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct get: average time: 2.86 ms
// 2. PropertyAccessor.GetInstanceValue<,>: average time: 4.80 ms (+1.95 ms / 168.15%)
// 3. PropertyAccessor.Get: average time: 11.56 ms (+8.71 ms / 404.98%)
// 4. System.Reflection.PropertyInfo.GetValue: average time: 17.05 ms (+14.20 ms / 597.12%)

// ==[Set Property - .NET Framework 4.8 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 4
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct set: average time: 3.63 ms
// 2. PropertyAccessor.SetInstanceValue<,>: average time: 12.05 ms (+8.42 ms / 331.91%)
// 3. PropertyAccessor.Set: average time: 18.20 ms (+14.57 ms / 501.41%)
// 4. System.Reflection.PropertyInfo.SetValue: average time: 186.50 ms (+182.87 ms / 5,137.78%)
// 
// ==[Get Property - .NET Framework 4.8 Results]================================================
// Iterations: 1,000,000
// Warming up: Yes
// Test cases: 4
// Calling GC.Collect: Yes
// Forced CPU Affinity: No
// Cases are sorted by time (quickest first)
// --------------------------------------------------
// 1. Direct get: average time: 3.51 ms
// 2. PropertyAccessor.GetInstanceValue<,>: average time: 11.12 ms (+7.62 ms / 317.21%)
// 3. PropertyAccessor.Get: average time: 15.01 ms (+11.50 ms / 428.04%)
// 4. System.Reflection.PropertyInfo.GetValue: average time: 120.99 ms (+117.49 ms / 3,450.32%)

Properties

CanRead Gets whether the property can be read (has get accessor).
CanWrite Gets whether the property can be written (has set accessor or is a ref property).
MemberInfo Gets the reflection member info of the accessed member.
(Inherited from MemberAccessor)

Methods

Equals Determines whether the specified Object is equal to the current MemberAccessor.
(Inherited from MemberAccessor)
Get(Object) Gets the value of the property with no index parameters. For static properties the instance parameter is omitted (can be ).
See the Remarks section of the Get(Object, Object) overload for details.
Get(Object, Object) Gets the value of the property with one index parameter. For static properties the instance parameter is omitted (can be ).
See the Remarks section of the Get(Object, Object) overload for details.
Get(Object, Object) Gets the value of the property. For static properties the instance parameter is omitted (can be ). If the property is not an indexer, then indexParameters parameter is omitted.
GetAccessor Gets a PropertyAccessor for the specified property.
GetHashCode Gets a hash code for the current MemberAccessor instance.
(Inherited from MemberAccessor)
GetInstanceValueTInstance, TProperty(TInstance) Gets the strongly typed value of a non-indexed instance property in a reference type. If the type of the property or the declaring instance is not known at compile time the non-generic Set methods can be used.
GetInstanceValueTInstance, TProperty(TInstance) Gets the strongly typed value of a non-indexed instance property in a value type. If the type of the property or the declaring instance is not known at compile time the non-generic Set methods can be used.
GetInstanceValueTInstance, TProperty, TIndex(TInstance, TIndex) Gets the strongly typed value of a single-parameter indexed property in a reference type. If the type of the property, the declaring instance or the index parameter is not known at compile time, or the indexer has more than one parameter, then the non-generic Set methods can be used.
GetInstanceValueTInstance, TProperty, TIndex(TInstance, TIndex) Gets the strongly typed value of a single-parameter indexed property in a value type. If the type of the property, the declaring instance or the index parameter is not known at compile time, or the indexer has more than one parameter, then the non-generic Set methods can be used.
GetStaticValueTProperty Gets the strongly typed value of a static property. If the type of the property is not known at compile time the non-generic Set methods can be used.
Set(Object, Object) Sets the property with no index parameters. For static properties the instance parameter is omitted (can be ).
See the Remarks section of the Set(Object, Object, Object) overload for details.
Set(Object, Object, Object) Sets the property with one index parameter. For static properties the instance parameter is omitted (can be ).
See the Remarks section of the Set(Object, Object, Object) overload for details.
Set(Object, Object, Object) Sets the property. For static properties the instance parameter is omitted (can be ). If the property is not an indexer, then indexParameters parameter is omitted.
SetInstanceValueTInstance, TProperty(TInstance, TProperty) Sets the strongly typed value of a non-indexed instance property in a value type. If the type of the property or the declaring instance is not known at compile time the non-generic Set methods can be used.
SetInstanceValueTInstance, TProperty(TInstance, TProperty) Sets the strongly typed value of a non-indexed instance property in a reference type. If the type of the property or the declaring instance is not known at compile time the non-generic Set methods can be used.
SetInstanceValueTInstance, TProperty, TIndex(TInstance, TProperty, TIndex) Sets the strongly typed value of a single-parameter indexed property in a value type. If the type of the property, the declaring instance or the index parameter is not known at compile time, or the indexer has more than one parameter, then the non-generic Set methods can be used.
SetInstanceValueTInstance, TProperty, TIndex(TInstance, TProperty, TIndex) Sets the strongly typed value of a single-parameter indexed property in a reference type. If the type of the property, the declaring instance or the index parameter is not known at compile time, or the indexer has more than one parameter, then the non-generic Set methods can be used.
SetStaticValueTProperty Sets the strongly typed value of a static property. If the type of the property is not known at compile time the non-generic Set methods can be used.
ToString Returns a String that represents the current MemberAccessor.
(Inherited from MemberAccessor)

Extension Methods

Convert Converts an Object specified in the obj parameter to the desired targetType.
See the Examples section of the generic ConvertTTarget(Object, CultureInfo) overload for an example.
(Defined by ObjectExtensions)
ConvertTTarget Converts an Object specified in the obj parameter to the desired TTarget.
(Defined by ObjectExtensions)
In Gets whether item is among the elements of set.
See the Examples section of the generic InT(T, T) overload for an example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvert Tries to convert an Object specified in the obj parameter to the desired targetType.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)
TryConvertTTarget Tries to convert an Object specified in the obj parameter to the desired TTarget.
See the Examples section of the ConvertTTarget(Object, CultureInfo) method for a related example.
(Defined by ObjectExtensions)

See Also