我可以创建一个采用值类型或引用类型但总是返回可空类型的generics方法

这是我的方法。 请注意,我返回通用参数R的等效可空类型:

  public static Nullable GetValue(this T a, Expression<Func> 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 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() .GetValue(x => x.MaximumLength) .GetValueOrDefault(50); 

我想对字符串使用相同的generics方法:

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

但它不会编译:

类型“R”必须是非可空值类型,以便在generics类型或方法“System.Nullable”中将其用作参数“T”

无法隐式转换类型’string?’ ‘串’

有没有什么技巧可以用来在这里获得相同的方法签名,然后让generics推断返回类型可以为null?

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

 //[StringLength(256)] //public string Name { get; set; } PropertyInfo info = ReflectionAPI.GetProperty(x => x.Name);//not null StringLengthAttribute attr = info.GetAttribute();//not null int? maximumLength = attr.GetValue(x => x.MaximumLength);//256 int? minimumLength = attr.GetValue(x => x.MinimumLength);//0 PropertyInfo info2 = ReflectionAPI.GetProperty(x => x.ID);//not null StringLengthAttribute attr2 = info2.GetAttribute();//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();//null int? maximumLength3 = attr3.GetValue(x => x.MaximumLength);//null int? minimumLength3 = attr3.GetValue(x => x.MinimumLength);//null 

这是我的ReflectionAPI的其余部分:

 public static class ReflectionAPI { public static Nullable GetValue(this T a, Expression<Func> 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(this PropertyInfo p) where T : Attribute { if (p == null) return null; return p.GetCustomAttributes(false).OfType().LastOrDefault(); } public static PropertyInfo GetProperty(Expression<Func> 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代表非可空值类型”。

您可以使用不同的方法,每个方法对R具有不同的约束 – 但是您必须提供不同的名称,或使用可怕的黑客有效地通过类型参数约束进行重载。

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

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

两个旁边:

  • 常规类型参数以T开头,例如TInputTResult
  • 你为什么要使用表达式树来获取GetValue ? 为什么不采取Func并执行它?

作为第二个要点的一个例子:

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