如何将泛型类限制为某些类型(包括本机数据类型)
本文关键字:类型 包括本 数据类型 泛型类 | 更新日期: 2023-09-27 18:10:55
我想创建一个泛型结构(基本上是一个数组),并将可能的类型限制为isserializable类型和一堆本地数据类型,如int,uint,float,double,char等。问题是我不能用接口标记这些本地数据类型,而且我的研究表明,在泛型类型约束构造(where子句)中不可能使用或关键字。问题是,我怎么才能实现呢?
如果你对上下文感兴趣:我有一个BinaryStream类负责从/到流读写。自定义 isserializable接口具有void Serialize(BinaryStream 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]);
}
}
您的研究已经为您提供了正确的信息- . 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>() {...}
}
具体的实现者可以像这里描述的那样找到
这是一个非常混乱的实现,但是如果不约束泛型类型并在构造函数中检查它,您会怎么想?如果类型T不在允许类型的白名单上,则抛出NotImplementedException