通过反射设置私有属性——找不到属性

问题描述 投票:0回答:0

TLDR:尽管具有正确的绑定标志,但无法使用反射在 this 类的实例上设置私有字段。

我正在进行 C# 单元测试以验证数据库的批量更新功能,特别是使用 Microsoft.Azure.Cosmos NuGet v3.32.0 的 Azure Cosmos。 在批量更新的实际逻辑中,我创建了一个 TransactionalBatch 并同步向该批处理添加单个操作,然后将整个批处理作为异步事务运行,如下所示:

var batch = _container.CreateTransactionalBatch(new PartitionKey(values.FirstOrDefault().PartitionKey)); 

foreach (var element in values) 
{ 
   batch.ReplaceItem(element.Id, element);            
}
var response = await batch.ExecuteAsync(cancellationToken);
var individualResults = response.AsEnumerable().ToList();

为了对此进行测试,我计划使用 Moq 来设置 CreateTransactionalBatch 以返回我自己创建的 TransactionalBatch,但它开始变得有点毛茸茸。 TransactionalBatch 类没有公共构造函数,枚举获取单个操作结果的结果字段是私有的。 这里是实际的类定义。

我的第一个想法是使用反射在 TransactionalBatchResponse 上设置所需的结果,所以我使用非常标准的反射逻辑来做到这一点:

 public static void SetPrivatePropertyValue<T>(this object obj, string propName, T val)
 {
     Type t = obj.GetType();
     if (t.GetProperty(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) == null)
                throw new ArgumentOutOfRangeException("propName", string.Format("Property {0} was not found in Type {1}", propName, obj.GetType().FullName));
     t.InvokeMember(propName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.SetProperty | BindingFlags.Instance, null, obj, new object[] { val });
}

在我尝试以这种方式创建的批处理响应中(我知道这不是很好,但是激活器没有无参数的 ctor):

var response = RuntimeHelpers.GetUninitializedObject(typeof(TransactionalBatchResponse)) as TransactionalBatchResponse;

最终看起来像这样:

var response = RuntimeHelpers.GetUninitializedObject(typeof(TransactionalBatchResponse)) as TransactionalBatchResponse;
ReflectionExtensions.SetPrivatePropertyValue(response, "results", individualResults);

当我尝试时,我的方法抛出错误:

System.ArgumentOutOfRangeException : Property results was not found in Type Microsoft.Azure.Cosmos.TransactionalBatchResponse

未经处理的是: System.MissingMethodException:找不到方法“Microsoft.Azure.Cosmos.TransactionalBatchResponse.results”。

当在 TransactionalBatchResponse 类中明确定义了一个结果字段时,我已经在反射方法上设置了 BindingFlags.Instance 和 BindingFlags.NonPublic。

这种预期行为是否与未初始化的对象有关,还是我遗漏了其他东西?我会假设由于该字段是在类中定义的,它应该仍然有效?

我也知道必须这样做可能表示代码有异味,我很可能只是将一些逻辑隔离并包装在其他地方以使其更易于测试,但我很好奇为什么会出现这种行为在这种特殊情况下可能会发生。

c# .net unit-testing system.reflection
© www.soinside.com 2019 - 2024. All rights reserved.