缓存反射的属性名称

时间:2012-01-09 03:35:37

标签: c# .net asp.net-mvc performance reflection

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

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

    return body.Member.Name;
}

给我变量名称。提到Reflection的每个人都说这对性能有害,所以我想缓存结果,这样每个var只能反映一次。例如:

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

我正在使用此Util来记录参数我希望在JQuery应用程序

中开始使用它来生成Asp.net Mvc3选择器
$('#'+ @(GetVariableName(()=> Model.FieldName))).Val();

有什么想法吗?

3 个答案:

答案 0 :(得分:2)

  

每个提到反思的人都说这对表现不利

当然,但在这种情况下,您已经拥有了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表达式版本,则不需要缓存任何内容。

答案 1 :(得分:1)

你应该可以做这样的事情......

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

答案 2 :(得分:0)

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

[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);
    }   
}