在Haskell中,我们可以这样做:
class Binary a where
encode :: a -> ByteString
decode :: ByteString -> a
instance Binary Int where
encode x = ...
decode bytes = ...
这定义了Binary
实现的接口Int
。我们现在可以将Int
转换为字节数组,反之亦然。我希望在C#中实现相同的功能,我的第一直觉就是创建接口:
interface Binary<T> {
byte[] Encode(T);
static T Decode(byte[]);
}
但这失败了,因为Decode
不允许static
。
我怎样才能尽可能干净地在C#中实现它?
请注意,我不想要一个可以创建一个空的&#34;或部分初始化T
,然后通过调用非static
Decode
填充它:这将是混乱的并且打开一个窗口,在此期间对象的使用是潜在的错误来源
谢谢!
答案 0 :(得分:2)
没有真正的方法可以直接将 static 方法添加到接口中,但是可以做的是将此方法添加到扩展类中或者在派生类中实现它(这几乎都是我们可以使用 static 方法):
但是在这种情况下我会做什么(如果由于某种原因我选择不使用标准的.Net序列化框架)我可能会创建自己的序列化程序类:
interface ISerializer<T> : IDisposable
{
virtual byte[] Serialize(T instance);
virtual T DeSerialize(byte[] stream);
}
Class MySerializer<T> : ISerializer<T>
{
public override byte[] Serialize(object instance)
{
// .. serialization logic
}
public override T DeSerialize(byte[] stream)
{
// .. deserialization logic
}
public void Dispose()
{
// .. dispose all managed resources here
}
}
class MyClass
{
}
用法:
MyClass instance = new MyClass();
MyClass newInstance = null;
using(ISerializer<MyClass> serializer = new MySerializer<MyClass>())
{
bytes[] bytes = serializer.Serialize(instance);
newInstance = serializer.DeSerialize(bytes);
}
答案 1 :(得分:1)
我通常最终会将这样的代码分成两种类型 - 一种是基类或接口(取决于我的需要),通常是通用的,它代表实际的数据,一种是带有静态和扩展方法的静态助手类。在这个例子中,我可能会做这样的事情:
public interface IBinary<T>
{
byte[] Encode(); // Alterantive definition as extension method below
}
public static class Binary
{
public static T Decode<T>(byte[] bytes) where T : IBinary<T>¨
{
// deserialization logic here
}
// If you want, you can define Encode() as an extension method instead:
public static byte[] Encode<T, TBinary>(this TBinary binary)
where TBinary : IBinary<T>
{
// serialization logic here
}
}
现在,您将通过创建类似
的类来使用此层次结构public class BinaryEncodableInteger : IBinary<int>
{
// must have this if defined in interface,
// but if defined as extension method you get it for free
public byte[] Encode()
{
// serialization logic here
}
}
并将该课程用作
var binInt = new BinaryEncodableInteger();
var bytes = binInt.Encode();
var decoded = Binary.Decode<BinaryEncodableInteger>(bytes);
答案 2 :(得分:0)
我认为interface
在C#和Haskell之间的差异太大,因为它在两种情况下都解决了这个问题。我宁愿使用implicit operators
。虽然他们没有提供这个问题的通用解决方案,但据我所知,因为他们也通过静态方法工作。
我定义了一个简单的Binary
类,其中包含byte
数组,以及来自int
的转换运算符。
class Binary
{
public Binary(byte[] value)
{
this.Value = value.ToArray();
}
public byte[] Value { get; private set; }
// User-defined conversion from Binary to int
public static implicit operator int(Binary b)
{
return b.Value[0] + (b.Value[1] << 8) + (b.Value[2] << 16) + (b.Value[3] << 24);
}
// User-defined conversion from int to Binary
public static implicit operator Binary(int i)
{
var result = new byte[4];
result[0] = (byte)(i & 0xFF);
result[1] = (byte)(i >> 8 & 0xFF);
result[2] = (byte)(i >> 16 & 0xFF);
result[3] = (byte)(i >> 24 & 0xFF);
return new Binary(result);
}
}
使用NUnit我可以按如下方式测试:
[TestCase(5, 0x05, 0x00, 0x00, 0x00)]
[TestCase(1500, 0xDC, 0x05, 0x00, 0x00)]
public void TestConvert(int i, byte b0, byte b1, byte b2, byte b3)
{
Binary testBinary = i;
Assert.AreEqual(b0, testBinary.Value[0]);
Assert.AreEqual(b1, testBinary.Value[1]);
Assert.AreEqual(b2, testBinary.Value[2]);
Assert.AreEqual(b3, testBinary.Value[3]);
int testInt = new Binary(new[] { b0, b1, b2, b3 });
Assert.AreEqual(testInt, i);
}
你可以去实现你自己的特定逻辑,但这应该证明原理。