填充摘要中没有 setter 的字段 class
Populating a field that has no setter in abstract class
我正在单元测试中使用 class EventRecordWrittenEventArgs
:
public sealed class EventRecordWrittenEventArgs : EventArgs {
public EventRecord EventRecord {get;}
public Exception EventException {get;}
}
我想用我自己的自定义数据填充 EventException
和 EventRecord
字段,因此我创建了我自己的上述 class 版本,名为 EventRecordWrittenEventArgsAdaptor
除了每个字段的 getter 之外,还有一个 setter。
问题是,EventRecord
是一个没有 setter 的抽象 class,这意味着我无法填充自己的自定义 EventRecord
对象(最终我的目标):
public abstract class EventRecord : IDisposable {
public abstract Guid? ProviderId {get;}
public abstract string TaskDisplayName {get;}
public abstract string OpcodeDispayName {get;}
...
}
我的第一个想法是创建一个从 EventRecord
派生的 EventRecordAdaptor
class 并给它每个字段一个 setter 但这不起作用:
public class EventRecordAdaptor : EventRecord {
public override Guid? ProviderId {get;set;} // "cannot override because EventRecord.Guid does not have an overrideable set accessor"
}
我应该如何创建我自己的 EventRecord
对象,我可以随心所欲地填充它?需要明确的是,我的最终目标是能够用我想要的任何东西填充 EventRecord
和 EventException
以进行单元测试。确定有办法填充此字段吗?
我不确定您的项目限制。如果您可以对抽象 class 进行以下更改,则可以将 GUID 传递给 EventRecord ,如下所示。
public abstract class EventRecord : IDisposable
{
private readonly Guid _id;
public EventRecord(Guid id)
{
_id = id;
}
public virtual Guid? ProviderId { get => _id; }
public abstract string TaskDisplayName { get; }
......
}
public class EventRecordAdaptor : EventRecord
{
public EventRecordAdaptor(Guid id) : base(id)
{
}
public override Guid? ProviderId => base.ProviderId;
...........
}
基于kirk-woll的评论:
public class EventRecordAdaptor : EventRecord
{
public EventRecordAdaptor(Guid? id)
{
_activityId = id;
}
private Guid? _activityId;
public override Guid? ActivityId => _activityId;
...
}
构造函数是内部的,所以基本上不能直接使用EventRecord
。这在使用外部 API 时很常见。在这种情况下,您的代码应该 不 使用本机 .NET 类型,而是将其包装在您可以模拟的接口中。有许多 Nuget 库,人们在其中为各种 .NET 类 创建了代理,而 EventRecord
的代理可能已经存在,您可以使用。如果没有,自己编写也很简单。
// this is the interface your code will use *instead of* EventRecord
// that exposes the properties and methods your code needs
public interface IEventRecord
{
public Guid? ProviderId {get;}
public string TaskDisplayName {get;}
public string OpcodeDispayName {get;}
}
// this is the concrete type you'll use in your production code
// to turn .NET's EventRecord into an IEventRecord
public EventRecordProxy : IEventRecord
{
private EventRecord _eventRecord;
public Guid? ProviderId => _eventRecord.ProviderId;
public string TaskDisplayName => _eventRecord.TaskDisplayName;
public string OpcodeDisplayName => _eventRecord.OpcodeDisplayName;
public EventRecordProxy(EventRecord er)
{
_eventRecord = er;
}
}
// this is the concrete type you'll use in your tests, with accessible properties
// (or if you're using a mocking framework, you can mock IEventRecord directly.)
public TestEventRecordProxy : IEventRecord
{
public Guid? ProviderId { get; set; }
public string TaskDisplayName { get; set}
public string OpcodeDispayName { get; set;}
}
是的,一开始这很麻烦,但总的来说这是一种更加灵活和模块化的设计。您不再受限于 EventRecord 的细节。如果您决定在其他地方获取该数据,或将多个对象组合在一起,您现在可以轻松地做到这一点。
我正在单元测试中使用 class EventRecordWrittenEventArgs
:
public sealed class EventRecordWrittenEventArgs : EventArgs {
public EventRecord EventRecord {get;}
public Exception EventException {get;}
}
我想用我自己的自定义数据填充 EventException
和 EventRecord
字段,因此我创建了我自己的上述 class 版本,名为 EventRecordWrittenEventArgsAdaptor
除了每个字段的 getter 之外,还有一个 setter。
问题是,EventRecord
是一个没有 setter 的抽象 class,这意味着我无法填充自己的自定义 EventRecord
对象(最终我的目标):
public abstract class EventRecord : IDisposable {
public abstract Guid? ProviderId {get;}
public abstract string TaskDisplayName {get;}
public abstract string OpcodeDispayName {get;}
...
}
我的第一个想法是创建一个从 EventRecord
派生的 EventRecordAdaptor
class 并给它每个字段一个 setter 但这不起作用:
public class EventRecordAdaptor : EventRecord {
public override Guid? ProviderId {get;set;} // "cannot override because EventRecord.Guid does not have an overrideable set accessor"
}
我应该如何创建我自己的 EventRecord
对象,我可以随心所欲地填充它?需要明确的是,我的最终目标是能够用我想要的任何东西填充 EventRecord
和 EventException
以进行单元测试。确定有办法填充此字段吗?
我不确定您的项目限制。如果您可以对抽象 class 进行以下更改,则可以将 GUID 传递给 EventRecord ,如下所示。
public abstract class EventRecord : IDisposable
{
private readonly Guid _id;
public EventRecord(Guid id)
{
_id = id;
}
public virtual Guid? ProviderId { get => _id; }
public abstract string TaskDisplayName { get; }
......
}
public class EventRecordAdaptor : EventRecord
{
public EventRecordAdaptor(Guid id) : base(id)
{
}
public override Guid? ProviderId => base.ProviderId;
...........
}
基于kirk-woll的评论:
public class EventRecordAdaptor : EventRecord
{
public EventRecordAdaptor(Guid? id)
{
_activityId = id;
}
private Guid? _activityId;
public override Guid? ActivityId => _activityId;
...
}
构造函数是内部的,所以基本上不能直接使用EventRecord
。这在使用外部 API 时很常见。在这种情况下,您的代码应该 不 使用本机 .NET 类型,而是将其包装在您可以模拟的接口中。有许多 Nuget 库,人们在其中为各种 .NET 类 创建了代理,而 EventRecord
的代理可能已经存在,您可以使用。如果没有,自己编写也很简单。
// this is the interface your code will use *instead of* EventRecord
// that exposes the properties and methods your code needs
public interface IEventRecord
{
public Guid? ProviderId {get;}
public string TaskDisplayName {get;}
public string OpcodeDispayName {get;}
}
// this is the concrete type you'll use in your production code
// to turn .NET's EventRecord into an IEventRecord
public EventRecordProxy : IEventRecord
{
private EventRecord _eventRecord;
public Guid? ProviderId => _eventRecord.ProviderId;
public string TaskDisplayName => _eventRecord.TaskDisplayName;
public string OpcodeDisplayName => _eventRecord.OpcodeDisplayName;
public EventRecordProxy(EventRecord er)
{
_eventRecord = er;
}
}
// this is the concrete type you'll use in your tests, with accessible properties
// (or if you're using a mocking framework, you can mock IEventRecord directly.)
public TestEventRecordProxy : IEventRecord
{
public Guid? ProviderId { get; set; }
public string TaskDisplayName { get; set}
public string OpcodeDispayName { get; set;}
}
是的,一开始这很麻烦,但总的来说这是一种更加灵活和模块化的设计。您不再受限于 EventRecord 的细节。如果您决定在其他地方获取该数据,或将多个对象组合在一起,您现在可以轻松地做到这一点。