使用PrivateObject设置没有setter的属性值

时间:2012-04-13 13:38:49

标签: c# unit-testing reflection

使用PrivateObject,我正在尝试创建ItemChange类的实例(找到here)。通过调试器以及Visual Studio 2008中的对象浏览器,我似乎无法找到与除{set}之外的ItemId属性相关的任何。以下是我正在使用的代码。

var itemChange = new PrivateObject(typeof(ItemChange));

itemChange.SetFieldOrProperty("ChangeType", _fixture.CreateAnonymous<ChangeType>());
itemChange.SetFieldOrProperty("ItemId", _fixture.CreateAnonymous<ItemId>());

我收到的错误是:

System.MissingMethodException : Method 'Microsoft.Exchange.WebServices.Data.ItemChange.ItemId' not found.

我尝试了BindingFlags的各种变体,但似乎没有任何帮助。如何设置没有setter且只有getter的属性?

修改

关于我的评论,我可以创建PrivateObject对象实例并设置ItemId的另一个内联类是ItemEvent类(找到here)。这个类很简单,因为当我调试并将类添加到我的监视列表时,我可以看到itemId作为私有变量。但是,在ItemChange类上执行相同的步骤我无法找到除属性本身之外的ItemId字段的任何跟踪只有有一个二传手。这是我对如何设置此属性感到困惑的地方。

最后,我无法访问允许我反编译该类并查看其内容的工具。

2 个答案:

答案 0 :(得分:2)

公共get-only属性不一定具有私有setter。如果您自己没有创建目标类,则可能需要获取像Reflector这样的反编译器来确定需要更改的内容,以便更改属性getter返回的值。

如果您发现自己经常需要执行此类操作,则可能需要考虑使用备用方法来控制第三方代码的行为,而无需使用适当的扩展挂钩。例如,Moles将允许您在不知道任何有关属性或类的内部信息的情况下将您自己想要的行为替换为getter。

答案 1 :(得分:1)

如果您尝试设置的属性是只读的,并且没有任何底层私有字段支持,那么您实际上无法设置它。例如,如果您具有以下属性:

public string ItemId
{
  get 
  {
    return "Test";
  }
}

你所做的就是将这个属性设置为另一个值。如果在查看调试器和/或反射中的对象字段时没有看到明显的后备字段,则可能是这种情况。

在这种情况下,如果我不得不猜测,我会说ItemId可能是一个只返回this.Item.Id的快捷属性。

编辑:

我的确如此。根据dotPeek,ItemChange.ItemId只返回Change.id,适当地进行类型转换。如果Change.serviceObject有值,则Change.id返回Change.serviceObject.GetId(),否则返回Change.id。根据您的情况,哪些适合您的情况取决于您所讨论的变化类型,根据MSDN:

  

当ChangeType属性的值为ChangeType.Delete或ChangeType.ReadFlagChange时,Item为null。

实际上,Change和ItemChange的实现是这样的:

public class Base 
{
  private Thing thing;
  private BaseId id;

  internal BaseId Id
  {
    get
    {
      return this.thing == null ? this.id : this.thing.GetId();
    }
  }
}

public class Child
{
  public ChildId ChildId
  {
    get 
    { 
      return (ChildId) this.Id; 
    }
  }
}

在实际的Change实施中,对象字段是名为serviceObject的{​​{3}},其GetId()方法返回ServiceId,其中也是id类型的ServiceId字段。要获取ItemChange对象的ItemId属性集,需要在对象的基类上设置其中一个或另一个内部字段(serviceObject字段优先于设置。)< / p>