在C#中等效C ++的reinterpret_cast

我想知道在C#中C ++的reinterpret_cast相当于什么?

这是我的样本:

 class Base { protected int counter = 0; } class Foo : Base { public int Counter { get { return counter; } } } Base b = new Base(); Foo f = b as Foo; // f will be null 

我没有异议为什么f应该是null,因为它应该是。 但如果它是C ++我可以写Foo f = reinterpret_cast(b); 得到我想要的东西。 我能做些什么来在C#中实现同样的目标?

PS。 我假设BaseFoo在数据方面是一致的。

[UPDATE]

这是一个简单的场景,其中reinterpret_cast可能会有所帮助:

考虑编写一个XXX-RPC库,您无法控制传入的参数,也无法控制要调用的服务的签名。 您的库应该使用给定的参数调用所请求的服务。 如果C#支持reinterpret_cast我可以简单地将给定参数reinterpret_cast为预期参数并调用服务。

讨论

正如一些答案所指出的那样,.Net在问题的范围内严格执行类型安全。 reinterpret_cast将是一种固有的不安全操作,因此实现它的可能方式可能是通过reflection序列化 ,而两者是相关的。

正如您在更新中提到的,可能的用途可能是RPC框架。 RPC库通常使用序列化/reflection,并且有几个可用的:

  • protobuf的远程
  • msgpack-RPC-CLI

所以,你可能不想自己写一个。

如果你的类Base使用公共属性,你可以使用AutoMapper :

 class Base { public int Counter { get; set; } // ... } 

 AutoMapper.Mapper.CreateMap(); Foo foo = AutoMapper.Mapper.Map(b); 

Foo根本不需要从Base派生。 它只需拥有您感兴趣的属性映射到。 但同样,您可能根本不需要两种类型 – 重新考虑体系结构可能是解决方案。

通常,不需要使用reinterpret_cast ,这是一种干净的体系结构,可以很好地适应.Net Framework中使用的模式。 如果您仍然坚持使用类似的东西,这里是使用紧凑型序列化库protobuf-net的解决方案。

序列化解决方案

你的课程:

 using System; using System.IO; using ProtoBuf; using ProtoBuf.Meta; [ProtoContract] [ProtoInclude(3, typeof(Foo))] class Base { [ProtoMember(1)] protected int counter = 0; public Base(int c) { counter = c; } public Base() { } } [ProtoContract] class Foo : Base { public int Counter { get { return counter; } } } 

和一个可运行的序列化 – 反序列化示例:

 class Program { static void Main(string[] args) { Base b = new Base(33); using (MemoryStream stream = new MemoryStream()) { Serializer.Serialize(stream, b); Console.WriteLine("Length: {0}", stream.Length); stream.Seek(0, SeekOrigin.Begin); Foo f=new Foo(); RuntimeTypeModel.Default.Deserialize(stream, f, typeof(Foo)); Console.WriteLine("Foo: {0}", f.Counter); } } } 

输出

 Length: 2 Foo: 33 

如果您不想在合同中声明派生类型,请参阅此示例…

如您所见,序列化非常紧凑。

如果要使用更多字段,可以尝试隐式序列化字段:

 [ProtoContract(ImplicitFields = ImplicitFields.AllFields)] 

一般的reinterpret_cast可能肯定可以通过这个序列化解决方案实现,也可以直接通过reflection来实现,但我现在不会投入时间。

这很有效。 是的,它就像你可能想象的那样邪恶令人敬畏。

 static unsafe TDest ReinterpretCast(TSource source) { var sourceRef = __makeref(source); var dest = default(TDest); var destRef = __makeref(dest); *(IntPtr*)&destRef = *(IntPtr*)&sourceRef; return __refvalue(destRef, TDest); } 

需要注意的一点是,如果你要将T[]U[]

  • 如果T大于U ,则边界检查将阻止您访问超过T[]原始长度的U元素
  • 如果T小于U ,则边界检查将允许您读取最后一个元素(实际上是缓冲区溢出漏洞)

您可能能够在C#中使用unsafe blocks和void*实现类似的行为:

 unsafe static TResult ReinterpretCast(this TOriginal original) where TOriginal : struct where TResult : struct { return *(TResult*)(void*)&original; } 

用法:

 Bar b = new Bar(); Foo f = b.ReinterpretCast(); f = ReinterpretCast(b); // this works as well 

未经测试。

我想,结构约束会使你的问题无效,但它们是必要的,因为类是由GC管理的,因此你不能指向它们。

C#在类型系统中没有允许你这样做的漏洞。 它知道什么类型的东西,不会允许你转换为不同的类型。 原因很明显。 向Foo添加字段时会发生什么?

如果你想要一种Foo,你需要创建一种Foo。 可能更好的路径是创建一个类型为Foo的构造函数,它将Base作为参数。

这是我的’实施’

 [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)] public unsafe static TResult ReinterpretCast(/*this*/ TOriginal orig) //refember ReferenceTypes are references to the CLRHeader //where TOriginal : struct //where TResult : struct { return Read(AddressOf(orig)); } 

确保在调用时知道自己在做什么,尤其是引用类型。

由于b只是Base的一个实例,因此永远无法将其强制转换为Foo的非null实例。 也许界面可能更适合您的需求?

如果Foo和Bar是结构,你可以做到

  [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)] public class MyFooBarHelper { [System.Runtime.InteropServices.FieldOffset(0)] public Foo theFoo; [System.Runtime.InteropServices.FieldOffset(0)] public Bar theBar; } 

但我不确定这会对物体起作用。