3

我很确定这是可能的,但是由于某种原因,我似乎无法弄清楚...我正在尝试从 Type 中创建一个扩展方法,它将把 Func 接收到该类型的属性中,并从 DefaultValueAttribute 中提取 DefaultValue。

我可以让它工作,但前提是我为 GetDefaultValue 函数调用指定类型参数。这是我目前拥有的代码:

个人实体:

public class Person
{
    public string FirstName { get; set; }

    [DefaultValue("1234")]
    public string DOB { get; set; }
}

调用方法:

//Messing around in LinqPad - .Dump() is LinqPad method

//Works
//typeof(Person).GetDefaultValue<Person, string>(x=>x.DOB).Dump();

//Trying to get to work
//Can't figure out how to get it to infer that TIn is of the Type type.....
typeof(Person).GetDefaultValue(x=> x.DOB).Dump();

这就是方法调用的去向……我只是想在我将其合并到我的实际程序中之前找出方法……一旦我弄清楚如何去做,错误检查就会发挥作用,或者放弃b/c是做不到的...

public static class Extensions
{
    //    Works
    //    public static TProperty GetDefaultValue<TModel, TProperty>(this Type type, Expression<Func<TModel, TProperty>> exp)
    //    {
    //        var property = typeof(TModel).GetProperties().ToList().Single(p => p.Name == GetFullPropertyName(exp));
    //        var defaultValue = (DefaultValueAttribute)property.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault();
    //        return (TProperty)defaultValue.Value;
    //    }

    //trying to get to work
    //I know that I can't do the following, but it is basically what I am trying to do...  I think!
    public static TProperty GetDefaultValue<TProperty>(this Type type, Expression<Func<typeof(type), TProperty>> exp) 
    {
        var property = type.GetProperties().ToList().Single(p => p.Name == GetFullPropertyName(exp));
        var defaultValue = (DefaultValueAttribute)property.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault();
        return (TProperty)defaultValue.Value;
    }

    //GetFullPropertyName c/o: http://stackoverflow.com/users/105570/
    //ref: http://stackoverflow.com/questions/2789504/
    public static string GetFullPropertyName<TModel, TProperty>(Expression<Func<TModel, TProperty>> exp)
    {
        MemberExpression memberExp;

        if (!TryFindMemberExpression(exp.Body, out memberExp))
               return String.Empty;

        var memberNames = new Stack<string>();
        do
            memberNames.Push(memberExp.Member.Name);
        while (TryFindMemberExpression(memberExp.Expression, out memberExp));

        return String.Join(".", memberNames.ToArray());
    }

    private static bool TryFindMemberExpression(Expression exp, out MemberExpression memberExp)
    {
        memberExp = exp as MemberExpression;
        if (memberExp != null)
            return true;

        if (IsConversion(exp) && exp is UnaryExpression)
        {
            memberExp = ((UnaryExpression)exp).Operand as MemberExpression;
            if (memberExp != null)
                return true;
        }    

        return false;
    }

    private static bool IsConversion(Expression exp)
    {
        return exp.NodeType == ExpressionType.Convert || exp.NodeType == ExpressionType.ConvertChecked;
    }
}

我疯了,还是这真的可能?预先感谢您的帮助!

4

1 回答 1

2

这不是它的工作方式——typeof(Person)没有名为 的属性DOB,但类型为 Person 的类有。您想要的是使您的扩展方法通用:

public static TValue GetDefaultValue<TClass, TValue>(this TClass val, Expression<Func<TClass, TValue>> getter) {
    var type = typeof(TClass);
    var property = type.GetProperties().ToList().Single(p => p.Name == GetFullPropertyName(exp));
    var defaultValue = (DefaultValueAttribute)property.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault();
    return (TProperty)defaultValue.Value;
}

并称之为:

Person somePerson = GetMeAPerson();
somePerson.GetDefaultValue(p=>p.DOB);

请注意,我没有测试过上述内容,但我在过去看到过类似的代码。也就是说,我怀疑您最初尝试做的这种方式并不是很吸引人,因为您需要先创建一个 Person 实例。

另一种可能更吸引人的方法是根本不使其成为扩展方法:

public static TValue GetDefaultValue<TClass, TValue>(Expression<Func<TClass, TValue>> getter) {
    var type = typeof(TClass);
    var property = type.GetProperties().ToList().Single(p => p.Name == GetFullPropertyName(exp));
    var defaultValue = (DefaultValueAttribute)property.GetCustomAttributes(typeof(DefaultValueAttribute), false).FirstOrDefault();
    return (TProperty)defaultValue.Value;
}

然后你可以在没有实例的情况下调用它,但推理不是很好):

var defaultValue = GetDefaultValue<Person, DateTime>(p => p.DOB);
于 2012-07-31T19:59:05.577 回答