我想创建一个通用结构(基本上是一个数组)并将可能的类型限制为ISerializable的类型和一堆本机数据类型,如int,uint,float,double,char等。问题是我无法标记这些具有接口的本机数据类型和我的研究表明,在泛型类型约束构造(where子句)中不可能使用类似或关键字的东西。所以问题是我怎么能意识到这一点?
如果您对上下文感兴趣:我有一个BinaryStream类负责从/向流读取和写入。 自定义 ISerializable接口具有函数void Serialize(BinaryStream f)
,可以从f读取或写入f(取决于f中的状态)。实际上,写入或读取当然是构成结构的本机数据类型。这些是通过f.Transfer(ref data)
读取或写入的。使用.NET框架中的标准BinarySerializer不是一种选择,因为它必须以自定义方式完成。
public class AutoArray<T> : ISerializable where T : ISerializable //or int or uint or float etc.
{
private uint n;
private T[] data;
public void Serialize(BinaryStream f)
{
f.Transfer(ref n);
for (int i = 0; i < n; i++)
if (data[i] is ISerializable) data[i].Serialize(f);
else f.Transfer(ref data[i]);
}
}
答案 0 :(得分:1)
您的研究已经向您提供了正确的信息 - .NET不允许您将泛型限制为某种抽象数字数据类型,因为它们(数值数据类型)没有任何公共接口。这是一个耻辱,有时是一个问题,但事实仍然如此。
如果你真的有非常通用的代码可以使用数字类型,那么你可以尝试用C ++ \ CLI实现你的类 - 它是C ++,所以它允许你使用模板,它是支持泛型的.NET语言:
// C# - use base interface for your serializer, define it in separate assembly(or directly in C++\CLI)
public interface IMySerializer<T> {...}
// C++\CLI - add the reference to the project with IMySerializer<T>
template<class Type>
public ref abstract class MyNumericSerializerBase : IMySerializer<Type> {...};
// C++\CLI - you can't use template class in C# - it must be specialized
public ref class MyIntSerializer : MyNumericSerializerBase<Int32> {...};
然后,将创建的C ++ \ CLI dll添加为项目的引用。好吧,你仍然需要为每种数字类型创建这样的MyIntSerializer
,但至少你不必复制所有的代码。为了有效地获得所需的IMySerializer<T>
,您可以使用某些工厂通过属性或IsAssignableFrom通过反映搜索特定的IMySerializer<T>
:
// C#
public class MySerializerFactory
{
public IMySerializer<T> GetSerializer<T>() {...}
}
这不是最简单的解决方案,但是我需要在计算中创建仅由数字类型不同的类型时使用。
修改强>
使用C ++ \ CLI是否有点过分?嗯,对于简单的情况,申请并不是很困难,但如果你不使用像
这样的东西template<class Type>
public ref abstract class MyNumericSerializerBase : IMySerializer<Type>
{
public:
Type GetValue(Type first, Type second)
{
return first + (second / 2); // The REAL advantage(and potential problems source) of C++\CLI templates
}
}
然后除了避免代码重复之外,这种方法没有真正的优点。并且,考虑到几乎没有数字类型,您可以在C#中实现特定的序列化:
// C#
public class MyInt32Serializer: IMySerializer<Int32> {...}
并使用相同的工厂(或定位器)模式:
// C#
public class MySerializerFactory
{
public IMySerializer<T> GetSerializer<T>() {...}
}
可以找到具体的实施者,如here
所述答案 1 :(得分:0)
这是一个非常混乱的实现,但您如何看待将泛型类型保持为无约束并在构造函数中检查它?如果类型T不在允许类型的白名单中,它基本上会抛出NotImplementedException。