在相同方法签名中的Func的TIn的扩展方法中使用此Type参数的类型

时间:2012-07-31 19:49:52

标签: c# generics types extension-methods func

我很确定这是可能的,但由于某种原因,我似乎无法解决这个问题...我正在尝试从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;
    }
}

我疯了,还是这有可能?提前感谢您的帮助!

1 个答案:

答案 0 :(得分: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);