FieldAccessor Class

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

Definition

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

Remarks

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

The non-generic Get and Set methods can be used to get and set the field in general cases.

If you know the field type at compile time, then you can use the generic GetStaticValue/SetStaticValue methods for static fields. If you know also the instance type, then the GetInstanceValue/SetInstanceValue methods can be used to access instance fields with better performance.

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 field by name rather than by a FieldInfo, then you can use the SetField and GetField methods in the Reflector class, which have some overloads with a fieldName parameter.

  Caution

The generic setter methods of this class in the .NET Standard 2.0 version throw a PlatformNotSupportedException for read-only fields. Use the non-generic Set method or reference the .NET Standard 2.1 build or any .NET Framework or .NET Core/.NET builds to setting support setting read-only fields by the generic setters.

Example

The following example compares the FieldAccessor class with FieldInfo 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 TestField;
    }

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

    static void Main(string[] args)
    {
        var instance = new TestClass();
        FieldInfo field = instance.GetType().GetField(nameof(TestClass.TestField));
        FieldAccessor accessor = FieldAccessor.GetAccessor(field);

        new PerformanceTest { TestName = $"Set Field - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => instance.TestField = 1, "Direct set")
            .AddCase(() => field.SetValue(instance, 1), "System.Reflection.FieldInfo.SetValue")
            .AddCase(() => accessor.Set(instance, 1), "FieldAccessor.Set")
            .AddCase(() => accessor.SetInstanceValue(instance, 1), "FieldAccessor.SetInstanceValue<,>")
            .DoTest()
            .DumpResults(Console.Out);

        new PerformanceTest<int> { TestName = $"Get Field - {PlatformName}", Iterations = 1_000_000 }
            .AddCase(() => instance.TestField, "Direct get")
            .AddCase(() => (int)field.GetValue(instance), "System.Reflection.FieldInfo.GetValue")
            .AddCase(() => (int)accessor.Get(instance), "FieldAccessor.Get")
            .AddCase(() => accessor.GetInstanceValue<TestClass, int>(instance), "FieldAccessor.GetInstanceValue<,>")
            .DoTest()
            .DumpResults(Console.Out);
    }
}

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

// ==[Set Field - .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: 2.83 ms
// 2. FieldAccessor.SetInstanceValue<,>: average time: 4.53 ms (+1.71 ms / 160.31%)
// 3. FieldAccessor.Set: average time: 10.84 ms (+8.01 ms / 383.41%)
// 4. System.Reflection.FieldInfo.SetValue: average time: 52.15 ms (+49.33 ms / 1,844.55%)
// 
// ==[Get Field - .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.83 ms
// 2. FieldAccessor.GetInstanceValue<,>: average time: 3.75 ms (+0.92 ms / 132.42%)
// 3. FieldAccessor.Get: average time: 10.18 ms (+7.35 ms / 359.81%)
// 4. System.Reflection.FieldInfo.GetValue: average time: 54.13 ms (+51.30 ms / 1,913.66%)

// ==[Set Field - .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.11 ms
// 2. FieldAccessor.SetInstanceValue<,>: average time: 11.45 ms (+8.34 ms / 367.99%)
// 3. FieldAccessor.Set: average time: 13.65 ms (+10.54 ms / 438.45%)
// 4. System.Reflection.FieldInfo.SetValue: average time: 99.95 ms (+96.84 ms / 3,211.03%)
// 
// ==[Get Field - .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: 2.15 ms
// 2. FieldAccessor.GetInstanceValue<,>: average time: 10.24 ms (+8.09 ms / 476.41%)
// 3. FieldAccessor.Get: average time: 10.56 ms (+8.41 ms / 491.29%)
// 4. System.Reflection.FieldInfo.GetValue: average time: 75.45 ms (+73.30 ms / 3,509.27%)

Properties

IsConstant Gets whether the field is a constant. Constant fields cannot be set.
IsReadOnly Gets whether the field is read-only.
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 Gets the value of the field. For static fields the instance parameter is omitted (can be ).
GetAccessor Gets a FieldAccessor for the specified field.
GetHashCode Gets a hash code for the current MemberAccessor instance.
(Inherited from MemberAccessor)
GetInstanceValueTInstance, TField(TInstance) Gets the strongly typed value of an instance field in a reference type. If the type of the field or the declaring instance is not known at compile time the non-generic Get method can be used.
GetInstanceValueTInstance, TField(TInstance) Gets the strongly typed value of an instance field in a value type. If the type of the field or the declaring instance is not known at compile time the non-generic Get method can be used.
GetStaticValueTField Gets the strongly typed value of a static field. If the type of the field is not known at compile time the non-generic Get method can be used.
Set Sets the field. For static fields the instance parameter is omitted (can be ).
SetInstanceValueTInstance, TField(TInstance, TField) Sets the strongly typed value of an instance field in a value type. If the type of the field or the declaring instance is not known at compile time the non-generic Set method can be used.
SetInstanceValueTInstance, TField(TInstance, TField) Sets the strongly typed value of an instance field in a reference type. If the type of the field or the declaring instance is not known at compile time the non-generic Set method can be used.
SetStaticValueTField Sets the strongly typed value of a static field. If the type of the field is not known at compile time the non-generic Set method 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