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:
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), Action<string>>();
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);
}
d.Invoke("new value");
Console.WriteLine(Foo.Name);
}
private static Action<string> 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);
var expr = Expression.Lambda<Action<string>>(assignExp, valueExp);
return expr.Compile();
}
}
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();
}
}