简体   繁体   中英

Cast a struct to a class inherits from the same Interface

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

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.

No.

Create a copy method to your FooClass that takes instance of IFoo , and perform necessary copy there.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM