C# 相当于C++';s重新解释C中的cast#

C# 相当于C++';s重新解释C中的cast#,c#,reinterpret-cast,C#,Reinterpret Cast,我想知道C++的在C中重新解释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应该是空的。但如果是C++

我想知道C++的
在C中重新解释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
应该是空的。但如果是C++,我就可以编写代码> fof= ReRealtType(b);<代码>并得到我想要的。我怎样才能在C#中实现同样的效果

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

[更新]

下面是一个简单的场景,在这个场景中,
reinterpret\u cast
可能会有所帮助:


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

因为b只是Base的一个实例,所以永远无法将其转换为非空的Foo实例。也许界面更适合您的需要?

C#的类型系统中没有允许您这样做的漏洞。它知道事物是什么类型的,不允许您转换为其他类型。原因相当明显。将字段添加到Foo时会发生什么

如果你想要一种类型的Foo,你需要创建一种类型的Foo。更好的方法是创建一个Foo类型的构造函数,该构造函数以Base作为参数。

正如一些答案所指出的,.Net在问题的范围内严格执行类型安全性。一个
重新解释\u cast
将是一个本质上不安全的操作,因此可能的实现方法是通过反射或序列化,而两者是相关的

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

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

如果您的类
Base
将使用公共属性,则可以使用:

以及一个可运行的序列化反序列化示例:

class Program
{
    static void Main(string[] args)
    {
        Base b = new Base(33);
        using (MemoryStream stream = new MemoryStream())
        {
            Serializer.Serialize<Base>(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);
        }
    }
}
如果不想在合约中声明派生类型,请参阅

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

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

[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]

通过这个序列化解决方案或者直接通过反射,可以实现一个通用的
重新解释
,但我现在不会投入时间。

在C中使用
不安全的
块和
无效*
,您可能会实现类似的行为:

unsafe static TResult ReinterpretCast(此原始版本)
where-TOriginal:struct
其中TResult:struct
{
返回*(TResult*)(void*)和原件;
}
用法:

Bar b = new Bar();
Foo f = b.ReinterpretCast<Foo>();
f = ReinterpretCast<Foo>(b); // this works as well
Bar b=新的Bar();
Foo f=b.ReinterpretCast();
f=重新解释广播(b);//这同样有效
没有测试


我想,结构约束否定了你的问题,但它们是必要的,因为类是由GC管理的,所以不允许有指向它们的指针。

这是我的“实现”

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public unsafe static TResult ReinterpretCast<TOriginal, TResult>(/*this*/ TOriginal orig)
        //refember ReferenceTypes are references to the CLRHeader
        //where TOriginal : struct
        //where TResult : struct
    {
        return Read<TResult>(AddressOf(orig));
    }
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInline)]
公共不安全静态树结果重新解释广播(/*此*/原始)
//refember ReferenceTypes是对CLR标头的引用
//where-TOriginal:struct
//其中TResult:struct
{
返回读取(AddressOf(orig));
}

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

这很有效。是的,它是你所能想象到的邪恶和可怕的

static unsafe TDest ReinterpretCast<TSource, TDest>(TSource source)
{
    var sourceRef = __makeref(source);
    var dest = default(TDest);
    var destRef = __makeref(dest);
    *(IntPtr*)&destRef = *(IntPtr*)&sourceRef;
    return __refvalue(destRef, TDest);
}
静态不安全TDest重新解释广播(TSource-source)
{
var sourceRef=\uuuu makeref(源);
var dest=默认值(TDest);
var destRef=uu makeref(dest);
*(IntPtr*)和destRef=*(IntPtr*)和sourceRef;
返回_refvalue(desref,TDest);
}
需要注意的一点是,如果您将
T[]
投射到和
U[]

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

如果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;            
    }

但我不确定这是否适用于对象。

这可能会有所帮助:@JLott,它帮不了什么忙
C#
C++
@JLott更安全,我读过那篇文章,但它与我的要求完全不同。@Dmitryedentsov AFAIK RPC库通过序列化和反序列化实现这一点,使用字符串作为中间媒介。人们可以将字符串视为字节序列,因此通过自然类比,将字符串重新解释为对象。一个C++类的代码> RealTytRask本质上是不安全的,因为你几乎不能说它是否正确工作。通过使用序列化(二进制,如果您需要紧凑的序列化),您可以获得对细纱的细粒度控制,特别是对部分故障的控制。正如其他评论者所注意到的,.Net类型的系统应该是安全的:)谢谢你的建议,但问题是肯定的。如果数据不一致,我会说它可能会抛出异常,它可能会返回null或…它可能会,但当你转换到错误的类型时它不会这样做。在我看来更安全、更稳定。如果你能在你的帖子中加入一些我们的对话,也许会更好。类似于“因为它在c中不受支持,这里有一个替代项…”。谢谢,太好了。最后一个想法,你是c
unsafe static TResult ReinterpretCast<TOriginal, TResult>(this TOriginal original)
    where TOriginal : struct
    where TResult : struct
{
    return *(TResult*)(void*)&original;
}
Bar b = new Bar();
Foo f = b.ReinterpretCast<Foo>();
f = ReinterpretCast<Foo>(b); // this works as well
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
    public unsafe static TResult ReinterpretCast<TOriginal, TResult>(/*this*/ TOriginal orig)
        //refember ReferenceTypes are references to the CLRHeader
        //where TOriginal : struct
        //where TResult : struct
    {
        return Read<TResult>(AddressOf(orig));
    }
static unsafe TDest ReinterpretCast<TSource, TDest>(TSource source)
{
    var sourceRef = __makeref(source);
    var dest = default(TDest);
    var destRef = __makeref(dest);
    *(IntPtr*)&destRef = *(IntPtr*)&sourceRef;
    return __refvalue(destRef, TDest);
}
    [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;            
    }