缓存反射的属性名称

本文关键字:属性 反射的 缓存 | 更新日期: 2023-09-27 18:19:50

我有一个类似于这个的方法:

static string GetVariableName<T>(Expression<Func<T>> expression)
{
    var body = expression.Body as MemberExpression;
    return body.Member.Name;
}

这给了我变量的名字。每个提到反射的人都说这对性能不好,所以我想缓存结果,这样每个变量只能发生一次反射。示例:

GetVariableName(() => Model.Field1) // Does Reflection.
GetVariableName(() => Model.Field2) // Does Reflection.
GetVariableName(() => Model.Field1) // Uses Cache.
GetVariableName(() => Model.Field2) // Uses Cache.

我正在使用这个Util来记录参数,我想开始使用它在Asp.net Mvc3应用程序中生成JQuery选择器

$('#'+ @(GetVariableName(()=> Model.FieldName))).Val();

有什么想法吗?

缓存反射的属性名称

每个提到反射的人都说这对的性能不利

当然,但在本例中,您已经拥有lambda表达式中的MemberInfo。编译器已经构建了表达式树。你不需要使用反射来获取它,这是很慢的。昂贵的是以下内容:

static string GetVariableName(string expression)
{
    // use reflection to find the property given the string and once you have the property
    // get its name
    ...
}

这就是ASP.NET MVC中所有强类型帮助程序的工作方式。如果使用强类型lambda表达式版本,则不需要缓存任何内容。

你应该能够做这样的事情。。。

class Foo {
    public Foo() {
        m_Field1Name = new Lazy<string>(() => GetVariableName(() => Field1));
        m_Field2Name = new Lazy<string>(() => GetVariableName(() => Field2));
    }
    public int Field1 { get; set; }
    public int Field2 { get; set; }
    public string Field1Name {
        get {
            return m_Field1Name.Value;
        }
    }
    readonly Lazy<string> m_Field1Name;
    public string Field2Name {
        get {
            return m_Field2Name.Value;
        }
    }
    readonly Lazy<string> m_Field2Name;
    public static string GetVariableName<T>(Expression<Func<T>> expression) {
        var body = expression.Body as MemberExpression;
        return body.Member.Name;
    }
}

缓存名称与非缓存名称的基准测试显示出显著差异。。。

class Program {
    static void Main(string[] args) {
        var foo = new Foo();
        const int count = 1000000;
        var sw = new Stopwatch();
        sw.Restart();
        for (int i = 0; i < count; ++i) {
            string name1 = foo.Field1Name;
            string name2 = foo.Field2Name;
        }
        sw.Stop();
        Console.Write("Cached:'t't");
        Console.WriteLine(sw.Elapsed);
        sw.Restart();
        for (int i = 0; i < count; ++i) {
            string name1 = Foo.GetVariableName(() => foo.Field1);
            string name2 = Foo.GetVariableName(() => foo.Field2);
        }
        sw.Stop();
        Console.Write("Non-cached:'t");
        Console.WriteLine(sw.Elapsed);
    }
}

此打印:

Cached:     00:00:00.0176370
Non-cached: 00:00:12.9247333

您是否考虑过使用属性?您可以对模型进行一次反思,然后缓存这些结果。

[AttributeUsage(AttributeTargets.Property, AllowMultiple= false)]
class JQueryFieldNameAttribute : Attribute {
    public string Name { get; private set; }
    public JQueryFieldNameAttribute(string name)
    {
        Name = name;
    }
}
class Model {
    [JQueryFieldName("#clientid")]
    public string Foo { get; set; }
}
void Main()
{
    var type = typeof(Model);
    var attributes = type.GetProperties()
                         .SelectMany (t => t.GetCustomAttributes(typeof(JQueryFieldNameAttribute), true));
    var cache = new Dictionary<int, IEnumerable<JQueryFieldNameAttribute>>();
    // Cache results for this type only
    cache.Add(type.GetHashCode(), attributes);
    foreach (JQueryFieldNameAttribute a in attributes)
    {
        Console.WriteLine (a.Name);
    }   
}