基类中的 C# 泛型类型

发布于 2024-08-02 10:49:41 字数 435 浏览 7 评论 0原文

我正在编写一个具有一组协议缓冲区(使用 protobuf-net)的系统,我想在一个抽象类中定义类似的东西,它们都继承了:

public byte[] GetBytes()

但是,协议缓冲区序列化器需要一个类型参数,是否有一些获取继承类类型的有效方法?

例子:

public byte[] GetBytes()
    {
        using (MemoryStream stream = new MemoryStream())
        {
            Serializer.Serialize<T /* what goes here? */>(stream, this);
            return stream.ToArray();
        }
    }

I'm writing a system that has a set of protocol buffers (using protobuf-net), I want to define something like this in an abstract class they all inherit off:

public byte[] GetBytes()

however, the protocol buffer serealiser requires a type argument, is there some efficient way to get the type of the inheriting class?

Example:

public byte[] GetBytes()
    {
        using (MemoryStream stream = new MemoryStream())
        {
            Serializer.Serialize<T /* what goes here? */>(stream, this);
            return stream.ToArray();
        }
    }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

辞慾 2024-08-09 10:49:42

就写“T”吧?

然后在你的类声明中:

public class M<T>

?

-- 编辑

然后当你继承它时:

public class Foo : M<Apple>

Just write "T" right?

and then in your class declaration:

public class M<T>

?

-- Edit

And then when you inherit it:

public class Foo : M<Apple>
北城挽邺 2024-08-09 10:49:42

你可以通过反射来做到这一点,但 protobuf-net 已经为你做到了。

只需将您的调用更改为:

Serializer.NonGeneric.Serialize(stream, this /* Takes an object here */);

这可以通过在运行时通过反射构建通用方法来实现。有关详细信息,请检查代码(第二个方法在这里)。

You can do this via reflection, but protobuf-net did it for you.

Just change your call to:

Serializer.NonGeneric.Serialize(stream, this /* Takes an object here */);

This works by building the generic method at runtime via reflection. For details, check the code (second method here).

若水般的淡然安静女子 2024-08-09 10:49:42

将基类定义为 BaseClass,然后派生类将 T 替换为序列化器类型 DerivedClass

您还可以指定类型参数的约束,例如

BaseClass<T> where T : SerializerBase

此处< /a> 是您可以应用的约束类型的描述。

Define your base class as BaseClass<T> and then your derived classes replace T with the serializer type DerivedClass<SerializerType>.

You can also specify constraints on the type argument e.g.

BaseClass<T> where T : SerializerBase

Here is a description of the types of constraints you can apply.

吹泡泡o 2024-08-09 10:49:42

实际上,您在这里不需要任何特殊的东西......因为 protobuf-net 尊重继承。如果你有:

[ProtoInclude(typeof(Foo), 20)]
[ProtoInclude(typeof(Bar), 21)]
public abstract class MyBase {
    /* other members */

    public byte[] GetBytes()
    {
        using(MemoryStream ms = new MemoryStream())
        {
            Serializer.Serialize<MyBase>(ms, this); // MyBase can be implicit
            return ms.ToArray();
        }
    }
}
[ProtoContract]
class Foo : MyBase { /* snip */ }
[ProtoContract]
class Bar : MyBase { /* snip */ }

那么它就会起作用。为了序列化数据,它总是从基本(契约)类型开始;所以即使你做了 Serializer.Serialize(stream, obj) 它要做的第一件事就是检测它有一个作为契约的基类,然后切换到 MyBase< /代码>。在反序列化期间,它将识别正确的派生(具体)类型并使用它,因此您也可以将 DeserializeMyBase 一起使用,它将构造一个 Foo 或 Bar 取决于原始数据是什么。

因此,以下内容基本相同:

Serializer.Serialize<BaseType>(dest, obj);
...
BaseType obj = Serializer.Deserialize<BaseType>(source);

Serializer.Serialize<DerivedType>(dest, obj);
...
DerivedType obj = Serializer.Deserialize<DerivedType>(source);

这里的主要区别在于变量的类型。

You don't actually need anything special here... since protobuf-net respects inheritance. If you have:

[ProtoInclude(typeof(Foo), 20)]
[ProtoInclude(typeof(Bar), 21)]
public abstract class MyBase {
    /* other members */

    public byte[] GetBytes()
    {
        using(MemoryStream ms = new MemoryStream())
        {
            Serializer.Serialize<MyBase>(ms, this); // MyBase can be implicit
            return ms.ToArray();
        }
    }
}
[ProtoContract]
class Foo : MyBase { /* snip */ }
[ProtoContract]
class Bar : MyBase { /* snip */ }

then it will work. To serialize the data, it always starts at the base (contract) type; so even if you did Serializer.Serialize<Foo>(stream, obj) the first thing it will do is detect that it has a base class that is a contract, and switch to MyBase. During deserialization it will identify the correct derived (concrete) type and use that, so you can use Deserialize with MyBase too, and it will construct a Foo or Bar depending on what the original data was.

Thus the following are largely identical:

Serializer.Serialize<BaseType>(dest, obj);
...
BaseType obj = Serializer.Deserialize<BaseType>(source);

and

Serializer.Serialize<DerivedType>(dest, obj);
...
DerivedType obj = Serializer.Deserialize<DerivedType>(source);

The main difference here is how the variables are typed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文