我正在以不同的格式和长度存储数据。我有一个类层次结构来表示这个:
abstract class BaseDataFormat{
abstract void InitalizeFromBytes(byte [] );
}
class DataFormat1 : BaseDataFormat{...} // data stored in 3 bytes
class DataFormat2 : BaseDataFormat{...} /// data stored in 4 bytes
当我读取数据时(比如从byte []中读取),我需要知道要读取的长度(字节数)并适当地创建相应的类型。 DataFormat1和DataFormat2具有不同的长度,因此如何在运行时获取此信息?即
Fcn<DATAFORMATTYPE>(...)
where DATAFORMATTYPE: BaseDataFormat, new();
{
DATAFORMATTYPE tmp = new DATAFORMATTYPE();
tmp.InitalizeFromBytes(ReadFromByteBuffer( ... someLength));
}
如何根据DATAFORMATTYPE对要读取的正确字节数进行编码?每个的长度感觉它应该是数据格式类型的静态属性,但静态属性不能被派生类覆盖,所以我不知道如何做到这一点。
长度可以编码为实例属性,但这似乎应该是在类级别(即静态)编码的知识。是否有设计模式来解决这个问题?
由于
答案 0 :(得分:2)
也许在BaseDataFormat
中有一个名为DataLength
的属性。要强制所有继承者设置值,请在BaseDataFormat
的构造函数中取长度,然后将该属性设置为数据长度。
示例:
abstract class BaseDataFormat
{
BaseDataFormat(int dataLength)
{
DataLength = dataLength;
}
public int DataLength { get; private set; }
abstract void InitalizeFromBytes(byte [] );
}
class DataFormat1 : BaseDataFormat
{
public DataFormat1() : base(3)
{
// ...
}
}
当然,它不是静态级别,但它是强制所有继承者的东西。
另一种方式是VirtualBlackFox如何建议,用属性装饰类。唯一的问题是AFAIK你不能强迫属性进入类,比如抽象成员。
答案 1 :(得分:2)
您如何知道在读取数据时要实例化的子类?从串行数据创建对象的更通用的解决方案是使用工厂模式。
可在以下位置找到此示例:http://en.wikipedia.org/wiki/Factory_method_pattern#Encapsulation
答案 2 :(得分:1)
我会为每个DataFormat构建Factory对象。或者可以将DataFormat
作为工厂,并调用实际数据对象Datum
或类似的东西。然后你可以实例化工厂,并传递字节缓冲区,它可以读取必要的字节并构造实际的数据对象。
答案 3 :(得分:0)
如果真的想要强制它是类的属性而不是实例的属性,则最好使用类上的属性。
但是你需要建立一个缓存,因为与直接访问相比,反射速度非常慢。
[AttributeUsage(AttributeTargets.Class)]
class ByteCountAttribute : Attribute
{
public int Value { get; private set; }
public ByteCountAttribute(int count)
{
Value = count;
}
}
[ByteCount(5)]
class DataFormat1 : BaseDataFormat{} // data stored in 3 bytes
[ByteCount(6)]
class DataFormat2 : BaseDataFormat{} /// data stored in 4 bytes
static Dictionary<Type, int> s_typeCache = new Dictionary<Type,int>();
public static int GetByteCount<T>() where T : BaseDataFormat
{
int result;
var type = typeof(T);
if (!s_typeCache.TryGetValue(type, out result))
{
var atts = type.GetCustomAttributes(typeof(ByteCountAttribute), false);
result = ((ByteCountAttribute)atts[0]).Value;
s_typeCache.Add(type, result);
}
return result;
}
(代码没有错误管理,但它可以工作)
正如darkassassin93所说,这种方法的一个问题是你不能强制执行它的存在,所以你必须记录这个属性是必要的,这与编译器为你完成工作的抽象属性相反。
答案 4 :(得分:0)
您所追求的称为通用值适配器。您可以定义一堆只公开某些常量的类,例如:
public static class Dimensions
{
public readonly struct Two : IInteger
{
public int Value => 2;
}
public readonly struct Three : IInteger
{
public int Value => 3;
}
}
然后,您可以定义一个类,该类将这些 IInteger
类型之一作为类型参数,并在运行时简单地提取它们的值:
public class Vector<T, D>
where D : IInteger, new()
{
protected T[] data;
public Vector()
{
data = new T[new D().Value];
}
}
您可以将其用作
var x = new Vector<float, Dimensions.Two>();