C# 相当于C++';s重新解释C中的cast#
我想知道C++的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中重新解释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;
}