为什么 Resharper 无法判断使用了初始化
Why Resharper can't tell initialization is used
我在编写单元测试时偶然发现了 Resharper 的建议。
Value assigned is not used by any execution path.
在下面的代码片段中。
[Test]
[TestCase((int)OddsRoundingModes.Floor)]
public void GetBaseOddsRoundingMode_WithCorrectRoundingMode_ShouldReturnCorrectRoundingMode(int oddsRoundingMode)
{
// Arrange
var oddsRoundingModeStr = oddsRoundingMode.ToString(); // <-- suggestion here
var mock = new Mock<IConstantsStorage>();
var oddsRoundingConfiguration = new OddsRoundingConfiguration(mock.Object);
mock.Setup(h => h.TryGetConstant(It.IsAny<string>(), It.IsAny<int>(), out oddsRoundingModeStr))
.Returns(true);
// Act
var roundingMode = oddsRoundingConfiguration.GetBaseOddsRoundingMode(0);
// Assert
Assert.AreNotEqual(roundingMode, OddsRoundingModes.None);
}
但是当我将其更改为在声明时未初始化时,模拟未正确设置并且测试失败,因为 oddsRoundingModeStr
未初始化并且模拟 return 为 null。
为什么 Resharper 看不到这个?
编辑:
public bool TryGetConstant(string name, int siteId, out string value)
{
value = RetrieveConstant(_constantsModel, name, siteId);
return value != null;
}
private string RetrieveConstant<T>(IConstantsModel<T> model, string constName, int siteId)
where T : IConstant, new()
{
if (model.Constants.TryGetValue(constName, out List<T> values))
{
var constant = values.FirstOrDefault(v => v.Name == constName && v.SiteIds.Contains(siteId));
if (constant != null)
{
return constant.ConstantValue;
}
}
return null;
}
Setup
接受表达式树 - Moq 分析该表达式树以创建最小起订量。在这种情况下,你基本上是说 Moq 应该创建 IConstantsModel
的实现,它接受任何字符串、任何 int、returns true 和你在 oddsRoundingModeStr
中提供的 returns 值作为 out
参数。所以在分析这个表达式树时,Moq 会提取 oddsRoundingModeStr
的实际值(捕获并存储在 compiler-generated class 的字段中)并且确实会使用它。 Resharper 无法意识到这一点,因此照常提供警告。
如何从表达式树中提取 out
变量值的小示例:
class Program {
static void Main(string[] args) {
int result = 2; // gives warning from your question
var back = ExtractOutValue(s => int.TryParse(s, out result));
Debug.Assert(back == result);
}
static int ExtractOutValue(Expression<Action<string>> exp) {
var call = (MethodCallExpression)exp.Body;
var arg = (MemberExpression) call.Arguments[1];
return (int) ((FieldInfo)arg.Member).GetValue(((ConstantExpression)arg.Expression).Value);
}
}
按照正常的 C# 语义,您将该变量初始化为的值是无关紧要的,因为 out
在为其分配新值之前无法读取数据。因此,resharper 通知是合适的。
我看到使用此代码可以实现非标准语义的几种方法:
out
是 CLR 级别的装饰 ref
。所以低级代码可以将其视为等同于 ref
.
void Main()
{
Ref r = R;
Out o = (Out)Delegate.CreateDelegate(typeof(Out), null, r.Method);
int i = 2;
o(out i);
i.Dump();
}
delegate void Out(out int x);
delegate void Ref(ref int x);
void R(ref int x)
{
x++;
}
Setup
接受委托,然后在闭包对象上使用私有反射。
Setup
采用 Expression<T>
,即 lambda 的语法树并以非标准方式解释表达式。
在此上下文中,lambda 表达式不是旨在执行的 C# 代码,而是本质上描述如何设置模拟的 DSL。
选项 3 似乎最有可能
我在编写单元测试时偶然发现了 Resharper 的建议。
Value assigned is not used by any execution path.
在下面的代码片段中。
[Test]
[TestCase((int)OddsRoundingModes.Floor)]
public void GetBaseOddsRoundingMode_WithCorrectRoundingMode_ShouldReturnCorrectRoundingMode(int oddsRoundingMode)
{
// Arrange
var oddsRoundingModeStr = oddsRoundingMode.ToString(); // <-- suggestion here
var mock = new Mock<IConstantsStorage>();
var oddsRoundingConfiguration = new OddsRoundingConfiguration(mock.Object);
mock.Setup(h => h.TryGetConstant(It.IsAny<string>(), It.IsAny<int>(), out oddsRoundingModeStr))
.Returns(true);
// Act
var roundingMode = oddsRoundingConfiguration.GetBaseOddsRoundingMode(0);
// Assert
Assert.AreNotEqual(roundingMode, OddsRoundingModes.None);
}
但是当我将其更改为在声明时未初始化时,模拟未正确设置并且测试失败,因为 oddsRoundingModeStr
未初始化并且模拟 return 为 null。
为什么 Resharper 看不到这个?
编辑:
public bool TryGetConstant(string name, int siteId, out string value)
{
value = RetrieveConstant(_constantsModel, name, siteId);
return value != null;
}
private string RetrieveConstant<T>(IConstantsModel<T> model, string constName, int siteId)
where T : IConstant, new()
{
if (model.Constants.TryGetValue(constName, out List<T> values))
{
var constant = values.FirstOrDefault(v => v.Name == constName && v.SiteIds.Contains(siteId));
if (constant != null)
{
return constant.ConstantValue;
}
}
return null;
}
Setup
接受表达式树 - Moq 分析该表达式树以创建最小起订量。在这种情况下,你基本上是说 Moq 应该创建 IConstantsModel
的实现,它接受任何字符串、任何 int、returns true 和你在 oddsRoundingModeStr
中提供的 returns 值作为 out
参数。所以在分析这个表达式树时,Moq 会提取 oddsRoundingModeStr
的实际值(捕获并存储在 compiler-generated class 的字段中)并且确实会使用它。 Resharper 无法意识到这一点,因此照常提供警告。
如何从表达式树中提取 out
变量值的小示例:
class Program {
static void Main(string[] args) {
int result = 2; // gives warning from your question
var back = ExtractOutValue(s => int.TryParse(s, out result));
Debug.Assert(back == result);
}
static int ExtractOutValue(Expression<Action<string>> exp) {
var call = (MethodCallExpression)exp.Body;
var arg = (MemberExpression) call.Arguments[1];
return (int) ((FieldInfo)arg.Member).GetValue(((ConstantExpression)arg.Expression).Value);
}
}
按照正常的 C# 语义,您将该变量初始化为的值是无关紧要的,因为 out
在为其分配新值之前无法读取数据。因此,resharper 通知是合适的。
我看到使用此代码可以实现非标准语义的几种方法:
out
是 CLR 级别的装饰ref
。所以低级代码可以将其视为等同于ref
.void Main() { Ref r = R; Out o = (Out)Delegate.CreateDelegate(typeof(Out), null, r.Method); int i = 2; o(out i); i.Dump(); } delegate void Out(out int x); delegate void Ref(ref int x); void R(ref int x) { x++; }
Setup
接受委托,然后在闭包对象上使用私有反射。Setup
采用Expression<T>
,即 lambda 的语法树并以非标准方式解释表达式。在此上下文中,lambda 表达式不是旨在执行的 C# 代码,而是本质上描述如何设置模拟的 DSL。
选项 3 似乎最有可能