我可以创建需要一个值类型或引用类型,但始终是一个通用的方法返回一个空类型 [英] Can I create a generic method that takes a value type or a reference type but always returns a nullable type

查看:98
本文介绍了我可以创建需要一个值类型或引用类型,但始终是一个通用的方法返回一个空类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的方法。请注意,我的泛型参数研究返回相当于可空类型:

 公共静态可空< R>的GetValue< T,R>(这件T一,表达式来; Func键< T,R>>表达式)
,其中T:属性
其中R:结构
{
如果(一个== NULL)
返回NULL;

的PropertyInfo P =的getProperty(表达);
如果(P == NULL)
返回NULL;

返回(R)p.GetValue(一,空);
}



我可以用它在呼叫得到这样一个属性的值

  //我不因为我想链中抛出无效或丢失的呼叫
//异常共同呼吁:
INT maximumLength4 = instance.GetProperty(X => x.ToString())
.GetAttribute< StringLengthAttribute>()
.GetValue(X => x.MaximumLength)
.GetValueOrDefault(50);



我想使用相同的通用方法处理字符串:

  //我想使用带有字符串的GetValue泛型方法以及整数
串erroMessage = instance.GetProperty(X => X的ToString())
.GetAttribute< StringLengthAttribute>()
.GetValue(X => x.ErrorMessage);



但它不会编译:



<块引用>

该型'R'必须是为了在泛型类型或方法使用它作为
参数'T'非空值类型System.Nullable



无法隐式转换类型'字符串?'到'字符串'




有没有什么绝招我可以用在这里得到相同的方法签名,但得到的仿制药来推断返回类型为一体,可以为空?



这是一些测试代码,以表明它适用于整数值:

  // [StringLength(256)] 
//公共字符串名称{;组; }
的PropertyInfo信息= ReflectionAPI.GetProperty<组织,字符串>(X => x.Name); //不为空
StringLengthAttribute ATTR = info.GetAttribute< StringLengthAttribute>(); //不为空
诠释? maximumLength = attr.GetValue(X => x.MaximumLength); // 256
诠释? minimumLength = attr.GetValue(X => x.MinimumLength); // 0

的PropertyInfo INFO2 = ReflectionAPI.GetProperty<组织,诠释>(X => x.ID); //不空
StringLengthAttribute attR2位= info2.GetAttribute< StringLengthAttribute>(); // null,因为标识不具有属性
诠释? maximumLength2 = attr2.GetValue(X => x.MaximumLength); //空
诠释? minimumLength2 = attr2.GetValue(X => x.MinimumLength); //空

//我可以使用一个实例
组织的实例=(组织)为null的getProperty扩展方法;
的PropertyInfo INFO3 = instance.GetProperty(X => x.ToString()); // null,因为它是一个方法调用不是一个属性
StringLengthAttribute attr3 = info3.GetAttribute< StringLengthAttribute>(); / /空
诠释? maximumLength3 = attr3.GetValue(X => x.MaximumLength); //空
诠释? minimumLength3 = attr3.GetValue(X => x.MinimumLength); //空



这是

 公共静态类ReflectionAPI $ b $:我的 ReflectionAPI 的其余部分b {

公共静态可空< R>的GetValue< T,R>(这件T一,表达式来; Func键< T,R>>表达式)
,其中T:属性
{
如果(A == NULL)
返回NULL;

的PropertyInfo P =的getProperty(表达);
如果(P == NULL)
返回NULL;

返回(R)p.GetValue(一,空);
}

公共静态牛逼的getAttribute< T>(此的PropertyInfo P),其中T:属性
{
如果(P == NULL)
返回空值;

返回p.GetCustomAttributes(假).OfType< T>()LastOrDefault()。
}

公共静态的PropertyInfo的getProperty< T,R>(表达式来; Func键< T,R>>表达式)
{
如果(表达式== NULL )
返回NULL;

MemberExpression memberExpression = expression.Body为MemberExpression;
如果(memberExpression == NULL)
返回NULL;

返回memberExpression.Member为的PropertyInfo;
}
}


解决方案

没有,没有个性签名可以做到这一点 - 有没有的方式说可空类型研究,这要么是研究本身引用类型,或可空< R> 对于非空值类型



你可以有不同的方法,每一个不同的约束上研究 - 但你要么必须提供不同的名称,或使用的 可怕的黑客来的有效的过载按类型参数约束。



我怀疑你应该基本上这里有两种不同的方法名称,为简单起见。所以签名:

 公共静态可空< R>的GetValue< T,R>(这件T一,表达式来; Func键< T,R>>表达式)
,其中T:属性
其中R:结构

公共静态ř GetReference< T,R>(这件T一,表达式来; Func键< T,R>>表达式)
,其中T:属性
其中R:类

二旁白:




  • 常规类型参数入手 T ,例如: TInput TResult

  • 为什么要使用表达式树在所有的的GetValue ?为什么不采取 Func键< T,R> 并执行它?



随着第二个小点的例子:

 公共静态可空< R>的GetValue< T,R>(这件T一,Func键< T,R> FUNC)
,其中T:属性
其中R:结构
{
如果(A == NULL )
返回NULL;

返回FUNC(一);
}


This is my method. Note that I am returning the equivalent nullable type for the generic parameter R:

    public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression)
        where T : Attribute
        where R : struct
    {
        if (a == null)
            return null;

        PropertyInfo p = GetProperty(expression);
        if (p == null)
            return null;

        return (R)p.GetValue(a, null);
    }

I can use it in a call to get the value of an attribute like this:

//I don't throw exceptions for invalid or missing calls 
//because I want to chain the calls together:
int maximumLength4 = instance.GetProperty(x => x.ToString())
                            .GetAttribute<StringLengthAttribute>()
                            .GetValue(x => x.MaximumLength)
                            .GetValueOrDefault(50);

I'd like to use the same generic method with strings:

//I'd like to use the GetValue generic method with strings as well as integers 
string erroMessage = instance.GetProperty(x => x.ToString())
                            .GetAttribute<StringLengthAttribute>()
                            .GetValue(x => x.ErrorMessage);

but it won't compile:

The type 'R' must be a non-nullable value type in order to use it as parameter 'T' in the generic type or method 'System.Nullable'

Cannot implicitly convert type 'string?' to 'string'

Is there any trick I can use to get the same method signature here and yet get generics to infer the return type as one that can be null?

This is some test code to show that it works for integer values:

//[StringLength(256)]
//public string Name { get; set; }
PropertyInfo info = ReflectionAPI.GetProperty<Organisation, String>(x => x.Name);//not null
StringLengthAttribute attr = info.GetAttribute<StringLengthAttribute>();//not null
int? maximumLength = attr.GetValue(x => x.MaximumLength);//256
int? minimumLength = attr.GetValue(x => x.MinimumLength);//0

PropertyInfo info2 = ReflectionAPI.GetProperty<Organisation, int>(x => x.ID);//not null
StringLengthAttribute attr2 = info2.GetAttribute<StringLengthAttribute>();//null because ID doesn't have the attribute
int? maximumLength2 = attr2.GetValue(x => x.MaximumLength);//null
int? minimumLength2 = attr2.GetValue(x => x.MinimumLength);//null

//I can use the GetProperty extension method on an instance
Organisation instance = (Organisation)null;
PropertyInfo info3 = instance.GetProperty(x => x.ToString());//null because its a method call not a property
StringLengthAttribute attr3 = info3.GetAttribute<StringLengthAttribute>();//null
int? maximumLength3 = attr3.GetValue(x => x.MaximumLength);//null
int? minimumLength3 = attr3.GetValue(x => x.MinimumLength);//null

And this is the rest of my ReflectionAPI:

public static class ReflectionAPI
{

    public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression)
        where T : Attribute
    {
        if (a == null)
            return null;

        PropertyInfo p = GetProperty(expression);
        if (p == null)
            return null;

        return (R)p.GetValue(a, null);
    }

    public static T GetAttribute<T>(this PropertyInfo p) where T : Attribute
    {
        if (p == null)
            return null;

        return p.GetCustomAttributes(false).OfType<T>().LastOrDefault();
    }

    public static PropertyInfo GetProperty<T, R>(Expression<Func<T, R>> expression)
    {
        if (expression == null)
            return null;

        MemberExpression memberExpression = expression.Body as MemberExpression;
        if (memberExpression == null)
            return null;

        return memberExpression.Member as PropertyInfo;
    }
}

解决方案

No, there's no individual signature that can do this - there's no way of saying "the nullable type of R, which is either R itself for a reference type, or Nullable<R> for a non-nullable value type".

You can have different methods, each with a different constraint on R - but then you either have to provide different names, or use horrible hacks to effectively overload by type parameter constraints.

I suspect you should basically have two different method names here, for simplicity. So signatures of:

public static Nullable<R> GetValue<T, R>(this T a, Expression<Func<T, R>> expression)
    where T : Attribute
    where R : struct

public static R GetReference<T, R>(this T a, Expression<Func<T, R>> expression)
    where T : Attribute
    where R : class

Two asides:

  • Conventionally type parameters start with T, e.g. TInput and TResult
  • Why are you using expression trees at all for GetValue? Why not just take a Func<T, R> and execute it?

As an example of the second bullet point:

public static Nullable<R> GetValue<T, R>(this T a, Func<T, R> func)
    where T : Attribute
    where R : struct
{
    if (a == null)
        return null;

    return func(a);
}

这篇关于我可以创建需要一个值类型或引用类型,但始终是一个通用的方法返回一个空类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆