Reputation: 16831
I wonder what's the equivalent of C++'s reinterpret_cast
in C#!?
Here's my sample:
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
I've got no objection why f
will be null since it should be. But if it was C++ I could have written Foo f = reinterpret_cast<Foo>(b);
and get what I wanted. What can I do to achieve the same in C#?
PS. I'm assuming that Base
and Foo
are consistent data-wise.
[UPDATE]
Here's a simple scenario where a reinterpret_cast
could be helpful:
Consider writing an XXX-RPC library where you've got no control over the incoming parameters nor the signature of services to call. Your library is supposed to call the asked service with the given parameters. If C# supported reinterpret_cast
I could simply reinterpret_cast
the given parameters into the expected ones and call the service.
Upvotes: 14
Views: 15108
Reputation: 6245
Many years later the .NET team introduced Unsafe.As<TFrom, TTo>
, the .NET's reinterpret cast basically. Make sure you know what you are doing.
This API is used to cast an object to the given type, suppressing the runtime's normal type safety checks. It is the caller's responsibility to ensure that the cast is legal. No InvalidCastException will be thrown.
Upvotes: 1
Reputation: 1349
If Foo and Bar were structs, you could do
[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;
}
but I'm not sure this would work on objects.
Upvotes: 4
Reputation: 5063
This works. And yes, it's as evil and as awesome as you can possibly imagine.
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);
}
One thing to note is that if you're casting a T[]
to and U[]
:
T
is bigger than U
, the bounds-checking will prevent you from accessing the U
elements past the original length of the T[]
T
is smaller than U
, the bounds-checking will let you read past the last element (effectively its a buffer overrun vulnerability)Upvotes: 12
Reputation: 3355
This is my 'implementation'
[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));
}
Ensure you know what your doing when you call it, especially with reference types.
Upvotes: 1
Reputation: 34499
You might be able to achieve similar behavior with unsafe
blocks and void*
in C#:
unsafe static TResult ReinterpretCast<TOriginal, TResult>(this TOriginal original)
where TOriginal : struct
where TResult : struct
{
return *(TResult*)(void*)&original;
}
Usage:
Bar b = new Bar();
Foo f = b.ReinterpretCast<Foo>();
f = ReinterpretCast<Foo>(b); // this works as well
Not tested.
The struct constraints nullify the point of your question, I guess, but they're necessary since classes are managed by the GC so you're not allowed to have pointers to them.
Upvotes: 4
Reputation: 3660
As some of the answers point out, .Net is enforcing type safety rigorously in the question's scope. A reinterpret_cast
would be an inherently unsafe operation, hence the possible ways to implement one would be either through reflection or serialization, whereas the two are related.
As you mentioned in an update, a possible use could be an RPC framework. RPC libraries typically use serialization/reflection anyway, and there are a couple of usable ones:
so, you might not want to write one yourself, perhaps.
If your class Base
would use public properties, you could use AutoMapper:
class Base
{
public int Counter { get; set; }
// ...
}
...
AutoMapper.Mapper.CreateMap<Base, Foo>();
Foo foo = AutoMapper.Mapper.Map<Foo>(b);
Where Foo
need not be derived from Base
at all. It just has to have the property you are interested in mapping onto. But again, you might not need two types at all - a rethinking of the architecture might be the solution.
Typically, there is no need to use reinterpret_cast
, by way of a clean architecture that fits nicely into the patterns used in the .Net Framework. If you still insist on having something like that, here's a solution using the compact serialization library protobuf-net.
Your classes:
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; } }
}
and a runnable serialization-deserialization example:
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);
}
}
}
outputting
Length: 2
Foo: 33
If you don't want to declare derived types in your contract, see this example...
As you see, the serialization is extremely compact.
If you want to use more fields, you might try implicit serialization of fields:
[ProtoContract(ImplicitFields = ImplicitFields.AllFields)]
A generic reinterpret_cast
might definitely be possible to implement either via this serialization solution, or directly via reflection, but I wouldn't invest the time at the moment.
Upvotes: 8
Reputation: 5674
C# doesn't have the hole in the type system which would allow you to do this. It knows what type things are and won't allow you to cast to a different type. The reasons for this are fairly obvious. What happens when you add a field to Foo?
If you want a type of Foo, you need to create a type of Foo. What might be a better route is creating a constructor of type Foo which takes a Base as parameter.
Upvotes: 1
Reputation: 7147
Since b is only an instance of Base you will never be able to cast it to a non null instance of Foo. Perhaps an interface might suit your needs better?
Upvotes: 0