检查方法是否正在访问 collection
Check if method is accessing collection
情况:
我卡在 c# 5.0 中,直到 2020 年之后我才能在当前环境中升级到 c# 6.0。同时,代码库中的空检查变得非常长,有时正在访问的属性在被访问之前没有被检查是否为 null。不久前,我创建了一个 TemporaryLanguageFeatures class,其中包含一些 C# 6.0 行为的复制品,例如 nameof。我决定创建一个 NullPropagation 方法,该方法采用 Expression<Func<T>>
并检查每个是否为 null,然后再继续该系列中的下一个 object。
问题:
当表达式包含对collection的访问并且collection为空或索引超出[=41的范围时=],我得到相关的空 collection 或索引超出范围错误。我可以访问表达式、创建的 LambdaExpression 和编译的 delegate/its MethodInfo。 编辑:我知道 c#6.0 不能防止这些情况,但是在我的方法中我仍然希望这样做。
没有 try/catch 我需要检查给定的调用是否会产生错误:
A)索引超出范围(collection有10个成员,表达式如下):
var answer = NullPropagation(() => item.Location.PhoneNumbers[500]);
B) collection为空(collection没有成员,表达式如下):
var answer = NullPropagation(() => item.Location.PhoneNumbers.First());
当前代码:
var members = new List<Expression>();
...填写collection等
var previousMethod = (MethodInfo) null;
var nullFound = members.Any(x =>
{
if (previousMethod != null && typeof(IEnumerable).IsAssignableFrom(previousMethod.ReturnType))
{
Console.WriteLine("HIT!");
//Todo: Detect collection empty/index out of range, return true;
}
previousMethod = method;
return Expression.Lambda(x).Compile().DynamicInvoke() == null;
}
...
经过广泛研究,我修复了索引访问问题,但我选择不更正 linq 问题,原因如下:
首先,可以检查该方法是否是以下任何可能由于空集合而引发错误的 linq 查询,然后检查集合上的 !.Any():
- 第一个
- 最后
- 单身
- 汇总
- 分钟
- 最大
- 平均
这里的问题是,可以向其中任何一个提供谓词,以限制集合的方式仍然是 return 错误。处理这种情况的选项是有限的。我们需要使用 try/catch 来处理它(这是我想避免的事情)或在 IEnumerable Linq 扩展中重新创建内部逻辑,报告发现空值而不是抛出错误。任何一种解决方案都是 hacky,对我来说不值得。如果您正在阅读本文并对这种方法非常感兴趣,我可以提供我放在一起作为概念证明的代码。
话虽如此,我确实纠正了索引访问问题,这是该问题的解决方案,在 HIT 所在的 if 块内! console writeline 在我的问题中:
var collectionAccessMethod = method.Body as MethodCallExpression;
if (collectionAccessMethod != null &&
previousMethod.ReturnType.GetProperties()
.Where(p => p.GetIndexParameters().Any())
.Select(p => p.GetGetMethod())
.Contains(collectionAccessMethod.Method))
{
var index = (int) Expression.Lambda(collectionAccessMethod.Arguments[0]).Compile().DynamicInvoke();
var collection = ((Func<IEnumerable>)Expression.Lambda(previousMethod).Compile().DynamicInvoke()).Invoke();
if (index > collection.Cast<object>().Count() - 1)
{
return true;
}
}
情况:
我卡在 c# 5.0 中,直到 2020 年之后我才能在当前环境中升级到 c# 6.0。同时,代码库中的空检查变得非常长,有时正在访问的属性在被访问之前没有被检查是否为 null。不久前,我创建了一个 TemporaryLanguageFeatures class,其中包含一些 C# 6.0 行为的复制品,例如 nameof。我决定创建一个 NullPropagation 方法,该方法采用Expression<Func<T>>
并检查每个是否为 null,然后再继续该系列中的下一个 object。
问题:
当表达式包含对collection的访问并且collection为空或索引超出[=41的范围时=],我得到相关的空 collection 或索引超出范围错误。我可以访问表达式、创建的 LambdaExpression 和编译的 delegate/its MethodInfo。 编辑:我知道 c#6.0 不能防止这些情况,但是在我的方法中我仍然希望这样做。没有 try/catch 我需要检查给定的调用是否会产生错误:
A)索引超出范围(collection有10个成员,表达式如下):
var answer = NullPropagation(() => item.Location.PhoneNumbers[500]);
B) collection为空(collection没有成员,表达式如下):
var answer = NullPropagation(() => item.Location.PhoneNumbers.First());
当前代码:
var members = new List<Expression>();
...填写collection等
var previousMethod = (MethodInfo) null;
var nullFound = members.Any(x =>
{
if (previousMethod != null && typeof(IEnumerable).IsAssignableFrom(previousMethod.ReturnType))
{
Console.WriteLine("HIT!");
//Todo: Detect collection empty/index out of range, return true;
}
previousMethod = method;
return Expression.Lambda(x).Compile().DynamicInvoke() == null;
}
...
经过广泛研究,我修复了索引访问问题,但我选择不更正 linq 问题,原因如下:
首先,可以检查该方法是否是以下任何可能由于空集合而引发错误的 linq 查询,然后检查集合上的 !.Any():
- 第一个
- 最后
- 单身
- 汇总
- 分钟
- 最大
- 平均
这里的问题是,可以向其中任何一个提供谓词,以限制集合的方式仍然是 return 错误。处理这种情况的选项是有限的。我们需要使用 try/catch 来处理它(这是我想避免的事情)或在 IEnumerable Linq 扩展中重新创建内部逻辑,报告发现空值而不是抛出错误。任何一种解决方案都是 hacky,对我来说不值得。如果您正在阅读本文并对这种方法非常感兴趣,我可以提供我放在一起作为概念证明的代码。
话虽如此,我确实纠正了索引访问问题,这是该问题的解决方案,在 HIT 所在的 if 块内! console writeline 在我的问题中:
var collectionAccessMethod = method.Body as MethodCallExpression;
if (collectionAccessMethod != null &&
previousMethod.ReturnType.GetProperties()
.Where(p => p.GetIndexParameters().Any())
.Select(p => p.GetGetMethod())
.Contains(collectionAccessMethod.Method))
{
var index = (int) Expression.Lambda(collectionAccessMethod.Arguments[0]).Compile().DynamicInvoke();
var collection = ((Func<IEnumerable>)Expression.Lambda(previousMethod).Compile().DynamicInvoke()).Invoke();
if (index > collection.Cast<object>().Count() - 1)
{
return true;
}
}