如何将泛型类限制为某些类型(包括本机数据类型)

本文关键字:类型 包括本 数据类型 泛型类 | 更新日期: 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