Reputation: 155
A challenge with a colleague about if there is any way to cast a struct to a class here the example that we have tried
namespace ConsoleApplication22
{
class Program
{
static void Main(string[] args)
{
IFoo fooS = new FooStruct();
fooS.Val = 5;
FooClass foo =(FooClass) fooS;
}
}
public interface IFoo
{
int Val { get; set; }
}
public struct FooStruct : IFoo
{
public int Val { get; set; }
}
public class FooClass : IFoo
{
//public FooClass(int val)
//{
//}
private int val;
public int Val
{
get { return val; }
set { val = value; }
}
}
}
but we got an invalid cast exception :D
are there any tricky way to extract the interface and assign it to the class given that an interface is a reference type and a class is a reference type and the class implements the interface
Upvotes: 2
Views: 2276
Reputation: 3833
The most hackish way I could think of (and one you should never, ever use!) is through the use of the Marshal
:
public unsafe static TDest UnsafeCast<TDest, TSrc>(object source)
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(TSrc))];
fixed (byte* b = buffer)
Marshal.StructureToPtr(source, new IntPtr(b), true);
fixed (byte* b = buffer)
return (TDest) Marshal.PtrToStructure(new IntPtr(b), typeof (TDest));
}
This literally marshals the data kept in FooClass
to FooStruct
, which allows it to be "cast" from a reference type to a value type.
You could optionally skip the second marshal if you use the FooStruct
type rather than a generic type parameter, by casting the buffer to the FooStruct
type from the buffer directly:
fixed (byte* b = buffer)
{
var s = (FooStruct*) b;
return *s;
}
Requires unsafe
compiler option, and should never ever be done in any sort of production environment - it's very slow and unpredictable.
Upvotes: 1
Reputation: 64477
You cannot directly cast between the two via the interface, it isn't allowed because they are not related to each other directly (ie, inheritance).
The compiler can catch a lot of this type of thing and not even allow the cast to compile. If the compiler cannot do it, the runtime does it. For explicit casting, the runtime will throw an exception on failed casts, for attempts at implicit casting (reference types only) the runtime returns null and does not throw an exception.
The type checking actually checks that FooStruct
is a FooClass
, which it can't be.
However, you can use the casting operators to convert between them making it look like a cast
class Program
{
static void Main(string[] args)
{
FooStruct f = new FooStruct();
f.Val = 2;
FooClass f2 = (FooClass)f;
Console.Read();
}
}
class FooClass : IFoo
{
public static explicit operator FooClass(FooStruct f)
{
FooClass foo = new FooClass();
foo.Val = f.Val;
return foo;
}
public int Val { get; set; }
}
struct FooStruct : IFoo
{
public int Val { get; set; }
public static explicit operator FooStruct(FooClass f)
{
FooStruct foo = new FooStruct();
foo.Val = f.Val;
return foo;
}
}
// This interface has little use in this scenario.
interface IFoo
{
int Val { get; set; }
}
Don't confuse casting with conversion. Also, be wary of applying interfaces to struct
types because boxing can occur.
Upvotes: 3
Reputation: 26268
No.
Create a copy method to your FooClass
that takes instance of IFoo
, and perform necessary copy there.
Upvotes: 2