简体   繁体   中英

C# - Faster way to get set public static fields instead of using Reflection.SetValue / GetValue

I have a scenario where I need to change public static fields during runtime. I understand that I can do it through reflection as below to get set the public static field I want, but it is really slow.

string typeName = "ABC";
string fieldName = "IsA";

Type.GetType(typeName ).GetField(fieldName ).SetValue(null, value);

var value = Type.GetType(typeName ).GetField(fieldName ).GetValue(null);

I would like to know is there any faster way to access such as using Reflection.Emit, Linq.Expression or other methods. As what I know currently most of them only support fields with an instance.

You can use expressions for this. You basically have three options:

  1. Reflection. Slow.
  2. Dynamic compiled expression. Fast.
  3. Typed compiled expression. Super fast.

In your case it's a bit tricky to go for typed expressions. I guess we cannot assume that all static properties will be of type string ? The second option allows you to easily create a fast setter for any field type.

Note that when compiling expressions, you must maintain a cache for the compiled delegates. The compilation step is very expensive!

class Program
{
    public class Foo
    {
        public static string Name;
    }

    public static void Main()
    {
        var delegateCache = new Dictionary<(string, string), Delegate>();
        
        var typeName = typeof(Foo).FullName;
        var fieldName = "Name";

        var key = (typeName, fieldName);

        // Caching is crucial!
        if (!delegateCache.TryGetValue(key, out var d))
        {
            d = CreateStaticSetter(typeName, fieldName);
            delegateCache.Add(key, d);
        }

        // For a strongly typed delegate, we would use Invoke() instead.
        d.DynamicInvoke("new value");

        Console.WriteLine(Foo.Name);
    }

    private static Delegate CreateStaticSetter(string typeName, string fieldName)
    {
        var type = Type.GetType(typeName) ?? throw new ArgumentException();
        var field = type.GetField(fieldName) ?? throw new ArgumentException();
        
        var valueExp = Expression.Parameter(field.FieldType, "value");
        var fieldExp = Expression.Field(null, field);
        var assignExp = Expression.Assign(fieldExp, valueExp);

        // TODO: Can be further optimized with a strongly typed delegate.
        var expr = Expression.Lambda(assignExp, valueExp);
        return expr.Compile();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM