我可以创建一个采用值类型或引用类型但始终返回可为空类型的泛型方法吗 [英] Can I create a generic method that takes a value type or a reference type but always returns a nullable type
问题描述
这是我的方法.请注意,我正在返回通用参数 R
的等效可空类型:
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);
但它不会编译:
类型R"必须是不可为空的值类型才能将其用作泛型类型或方法System.Nullable"中的参数T"
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'
有什么技巧可以让我在这里获得相同的方法签名,但又可以使用泛型将返回类型推断为可以为 null 的类型吗?
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
这是我的 ReflectionAPI
的其余部分:
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;
}
}
推荐答案
不,没有单独的签名可以做到这一点 - 没有办法说R
的可空类型,要么R
本身用于引用类型,或者 Nullable
用于不可为 null 的值类型".
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".
您可以使用不同的方法,每种方法对 R
都有不同的约束 - 但是您要么必须提供不同的名称,要么使用 可怕的黑客通过类型参数有效重载约束.
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
两点:
- 传统的类型参数以
T
开头,例如TInput
和TResult
- 为什么要为
GetValue
使用表达式树?为什么不直接使用Func
并执行它?
- Conventionally type parameters start with
T
, e.g.TInput
andTResult
- Why are you using expression trees at all for
GetValue
? Why not just take aFunc<T, R>
and execute it?
以第二个要点为例:
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屋!