IRecordAccessor
IAccessor └── IRecordAccessor └── IRecordAccessor<Container> └── IRecordAccessor<Container, Content>
IRecordAccessor describes writers that access a record. Record can exist as class, struct, memory-span or stream.
/// <summary>Record accessor</summary>
public interface IRecordAccessor : IAccessor, IFieldContainerAccessor, IDefaultConstructorAccessor, IConstructorAccessor, IDeconstructorAccessor, IContainerAccessor { }
/// <summary>Accessor for container that has fields.</summary>
public interface IFieldContainerAccessor : IAccessor
{
/// <summary>Fields.</summary>
IContentAccessor[] Fields { get; set; }
}
IRecordAccessor<Container> and IRecordAccessor<Container, Container> describe accessor for Container type and optionally Content type.
/// <summary>Record accessor of <typeparamref name="Container"/>.</summary>
public interface IRecordAccessor<Container> : IRecordAccessorT, IFieldContainerAccessor<Container>, IAccessor<Container>, IDefaultConstructorAccessor<Container>, IConstructorAccessor<Container>, IDeconstructorAccessor<Container>, IContainerAccessor<Container> where Container : notnull { }
/// <summary>Record accessor of <typeparamref name="Container"/>.</summary>
public interface IRecordAccessor<Container, Content> : IRecordAccessor<Container>, IRecordAccessorOf<Content>, IFieldContainerAccessor<Container, Content> where Container : notnull { }
IRecordVisitor and IRecordVisitorT are visitor interfaces for IAccessorBase.Accept(IAccessorVisitor).
/// <summary>Base interface for record visitor</summary>
public interface IRecordVisitor : IAccessorVisitor
{
/// <summary>Try visit <paramref name="recordAccessor"/>.</summary>
/// <returns>true to continue visitation</returns>
bool VisitRecordAccessor(IRecordAccessor recordAccessor);
}
/// <summary>Base interface for record visitor</summary>
public interface IRecordVisitorT : IAccessorVisitor
{
/// <summary>Try visit <paramref name="RecordAccessor"/>.</summary>
/// <returns>true to continue visitation</returns>
bool VisitRecordAccessor<Container>(IRecordAccessor<Container> recordAccessor) where Container : notnull;
}
/// <summary>Base interface for record visitor</summary>
public interface IRecordVisitorT2 : IAccessorVisitor
{
/// <summary>Try visit <paramref name="RecordAccessor"/>.</summary>
/// <returns>true to continue visitation</returns>
bool VisitRecordAccessor<Container, Content>(IRecordAccessor<Container, Content> recordAccessor) where Container : notnull;
}
RecordAccessor
AccessorBase └── RecordAccessor └── RecordAccessor<Container> └── RecordAccessor<Container, Content>
RecordAccessor is implementation without specific container and content types.
IRecordAccessor accessor = new RecordAccessor()
{
Fields = Array.Empty<IContentAccessor>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
RecordAccessor<Container> is implementation for specific container.
IRecordAccessor accessor = new RecordAccessor<MyRecord>()
{
Fields = Array.Empty<IContentAccessor<MyRecord>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
RecordAccessor<Container, Content> is implementation for specific Container and Content types.
IRecordAccessor accessor = new RecordAccessor<MyRecord, object>()
{
Fields = Array.Empty<IContentAccessor<MyRecord, object>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
RecordAccessor.Create(containerType) constructs IRecordAccessor<Container> with run-time types. There are extension method a setters for each field.
IRecordAccessor accessor =
RecordAccessor.Create(typeof(MyRecord))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
RecordAccessor.Create(containerType, contentType) constructs IRecordAccessor<Container, Content>.
IRecordAccessor accessor =
RecordAccessor.Create(typeof(MyRecord), typeof(object))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor<MyRecord, object>>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
Query
AccessorRequest(target) requests for IAccessor depending on type target.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IAccessor> request = new AccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
RecordAccessorRequest(target) requests for IRecordAccessor<Record>.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
RecordAccessorRequest(target) can also request for IRecordAccessor<Record, Element>.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord), typeof(object));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord, object> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord, object>>(request);
// Create record
var record = new MyRecord(11, "A");
// Write as boxed object
accessor.Fields[0].Writer.Write(12, record);
// Read as object
object label = accessor.Fields[1].Reader.Read(record);
RecordAccessorRequest is specifically a request for specific writers. Each can be assigned with explicit customization.
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest
{
Constructor = new ConstructorRequest(target),
Deconstructor = new DeconstructorRequest(target),
DefaultConstructor = new DefaultConstructorRequest(target),
Fields = new ContentAccessorsRequest(target),
IsAssigned = new IsAssignedRequest(target),
Unassign = new UnassignRequest(target),
ContainerType = new ContainerTypeRequest(target),
ContentType = new ContentTypeRequest(target),
};
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
Example class.
public record MyRecord(int Id, string Label);
Usage
.DefaultConstructor creates a record with default value.
MyRecord record = accessor.DefaultConstructor.Read();
.Constructor creates a record from tuple.
MyRecord record = accessor.Constructor.ReadAs<(int id, string label), MyRecord>((10, "Hello"));
.Deconstructor reads values as an tuple.
MyRecord record = new MyRecord(10, "Hello");
(int id, string label) = accessor.Deconstructor.ReadAs<MyRecord, (int id, string label)>(record);
.Fields contains record fields.
MyRecord record = new MyRecord(10, "Hello");
accessor.Fields[0].Writer.WriteAs<int, MyRecord>(11, record);
int id = accessor.Fields[0].Reader.ReadAs<MyRecord, int>(record);
.IsAssigned tests whether a record is assigned in container.
MyRecord record = new MyRecord(10, "Hello");
bool nonNull = accessor.IsAssigned.Read(record);
.Unassign removes record at container.
MyRecord record = new MyRecord(10, "Hello");
accessor.Unassign.Write(default, ref record);
Notes
A ref is used when accessing value-typed container.
// Create accessor
IRecordAccessor<MyStruct> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IRecordAccessor<MyStruct>>();
// Create value-typed record on stack
MyStruct record = new MyStruct(10, "Hello");
// Write id
accessor.Fields[0].Writer.WriteAs<int, MyStruct>(11, ref record);
public record struct MyStruct(int Id, string Label);
Boxed value-types can be accessed as object.
// Create accessor
IRecordAccessor<MyStruct> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IRecordAccessor<MyStruct>>();
// Create value-typed record into heap
object record = new MyStruct(10, "Hello");
// Write id
accessor.Fields[0].Writer.TypeCast<int, object>().Write(11, record);
Full Example
Full example
using System;
using Avalanche.Accessor;
using Avalanche.DataType;
using Avalanche.Service;
using Avalanche.Utilities;
using Avalanche.Writer;
using Microsoft.Extensions.DependencyInjection;
public class recordaccessor
{
public static void Run()
{
{
// <00>
IRecordAccessor accessor = new RecordAccessor()
{
Fields = Array.Empty<IContentAccessor>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </00>
}
{
// <01>
IRecordAccessor accessor = new RecordAccessor<MyRecord>()
{
Fields = Array.Empty<IContentAccessor<MyRecord>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </01>
}
{
// <02>
IRecordAccessor accessor = new RecordAccessor<MyRecord, object>()
{
Fields = Array.Empty<IContentAccessor<MyRecord, object>>(),
DefaultConstructor = null!,
Constructor = null!,
Deconstructor = null!,
IsAssigned = null!,
Unassign = null!
}.SetReadOnly();
// </02>
}
{
// <03>
IRecordAccessor accessor =
RecordAccessor.Create(typeof(MyRecord))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
// </03>
}
{
// <04>
IRecordAccessor accessor =
RecordAccessor.Create(typeof(MyRecord), typeof(object))
.SetConstructor(null!)
.SetDeconstructor(null!)
.SetDefaultConstructor(null!)
.SetFields(Array.Empty<IContentAccessor<MyRecord, object>>())
.SetIsAssigned(null!)
.SetUnassign(null!)
.SetReadOnly();
// </04>
}
{
// <10>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IAccessor> request = new AccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
// </10>
}
{
// <11>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
// </11>
}
{
// <11B>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord), typeof(object));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest(target);
// Issue request
IRecordAccessor<MyRecord, object> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord, object>>(request);
// Create record
var record = new MyRecord(11, "A");
// Write as boxed object
accessor.Fields[0].Writer.Write(12, record);
// Read as object
object label = accessor.Fields[1].Reader.Read(record);
// </11B>
}
{
// <12>
// Create service
IService service = Services.Create(NetAccessorHandlers.Instance);
// Create container target
IContainerTarget target = new NetRecord(typeof(MyRecord));
// Create request
IRequestFor<IRecordAccessor> request = new RecordAccessorRequest
{
Constructor = new ConstructorRequest(target),
Deconstructor = new DeconstructorRequest(target),
DefaultConstructor = new DefaultConstructorRequest(target),
Fields = new ContentAccessorsRequest(target),
IsAssigned = new IsAssignedRequest(target),
Unassign = new UnassignRequest(target),
ContainerType = new ContainerTypeRequest(target),
ContentType = new ContentTypeRequest(target),
};
// Issue request
IRecordAccessor<MyRecord> accessor = service.GetRequired<IRequest, IRecordAccessor<MyRecord>>(request);
// </12>
}
{
IRecordAccessor<MyRecord> accessor = Services.Create(NetAccessorHandlers.Instance).GetRequiredService<IRecordAccessor<MyRecord>>();
{
// <51>
MyRecord record = accessor.DefaultConstructor.Read();
// </51>
}
{
// <52>
MyRecord record = accessor.Constructor.ReadAs<(int id, string label), MyRecord>((10, "Hello"));
// </52>
}
{
// <53>
MyRecord record = new MyRecord(10, "Hello");
(int id, string label) = accessor.Deconstructor.ReadAs<MyRecord, (int id, string label)>(record);
// </53>
}
{
// <54>
MyRecord record = new MyRecord(10, "Hello");
accessor.Fields[0].Writer.WriteAs<int, MyRecord>(11, record);
int id = accessor.Fields[0].Reader.ReadAs<MyRecord, int>(record);
// </54>
}
{
// <62>
MyRecord record = new MyRecord(10, "Hello");
bool nonNull = accessor.IsAssigned.Read(record);
// </62>
}
{
// <63>
MyRecord record = new MyRecord(10, "Hello");
accessor.Unassign.Write(default, ref record);
// </63>
}
}
{
// <71>
// Create accessor
IRecordAccessor<MyStruct> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IRecordAccessor<MyStruct>>();
// Create value-typed record on stack
MyStruct record = new MyStruct(10, "Hello");
// Write id
accessor.Fields[0].Writer.WriteAs<int, MyStruct>(11, ref record);
// </71>
}
{
// <72>
// Create accessor
IRecordAccessor<MyStruct> accessor =
Services.Create(NetAccessorHandlers.Instance)
.GetRequiredService<IRecordAccessor<MyStruct>>();
// Create value-typed record into heap
object record = new MyStruct(10, "Hello");
// Write id
accessor.Fields[0].Writer.TypeCast<int, object>().Write(11, record);
// </72>
}
}
// <100>
public record MyRecord(int Id, string Label);
// </100>
// <101>
public record struct MyStruct(int Id, string Label);
// </101>
}