C# - 更快地设置 public 静态字段而不是使用 Reflection.SetValue / GetValue
C# - Faster way to get set public static fields instead of using Reflection.SetValue / GetValue
我有一个场景需要在运行时更改 public 静态字段。我知道我可以通过如下反射来设置我想要的 public 静态字段,但它真的很慢。
string typeName = "ABC";
string fieldName = "IsA";
Type.GetType(typeName ).GetField(fieldName ).SetValue(null, value);
var value = Type.GetType(typeName ).GetField(fieldName ).GetValue(null);
我想知道有没有更快的访问方法,例如使用Reflection.Emit、Linq.Expression或其他方法。据我所知,目前大多数只支持带有实例的字段。
您可以为此使用表达式。你基本上有三个选择:
- 反思。慢。
- 动态编译表达式。快。
- 类型化的编译表达式。超级快。
在您的情况下,使用类型化表达式有点棘手。我想我们不能假设所有静态属性都是 string
类型?第二个选项允许您轻松地为任何字段类型创建快速 setter。
请注意,在编译表达式时,您必须为已编译的委托维护一个缓存。编译步骤非常昂贵!
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();
}
}
我有一个场景需要在运行时更改 public 静态字段。我知道我可以通过如下反射来设置我想要的 public 静态字段,但它真的很慢。
string typeName = "ABC";
string fieldName = "IsA";
Type.GetType(typeName ).GetField(fieldName ).SetValue(null, value);
var value = Type.GetType(typeName ).GetField(fieldName ).GetValue(null);
我想知道有没有更快的访问方法,例如使用Reflection.Emit、Linq.Expression或其他方法。据我所知,目前大多数只支持带有实例的字段。
您可以为此使用表达式。你基本上有三个选择:
- 反思。慢。
- 动态编译表达式。快。
- 类型化的编译表达式。超级快。
在您的情况下,使用类型化表达式有点棘手。我想我们不能假设所有静态属性都是 string
类型?第二个选项允许您轻松地为任何字段类型创建快速 setter。
请注意,在编译表达式时,您必须为已编译的委托维护一个缓存。编译步骤非常昂贵!
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();
}
}