简体   繁体   English

将结构转换为继承自同一接口的类

[英]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 但是我们得到了一个无效的强制转换异常: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. 对于显式强制转换,运行时将在失败的强制转换时抛出异常,对于尝试隐式强制转换(仅引用类型),运行时将返回null且不引发异常。

The type checking actually checks that FooStruct is a FooClass , which it can't be. 类型检查实际上检查FooStruct 是否是 FooClass ,它不是。

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. 另外,请警惕将接口应用于struct类型,因为可能发生装箱。

No. 没有。

Create a copy method to your FooClass that takes instance of IFoo , and perform necessary copy there. 创建一个使用IFoo实例的FooClass复制方法,并在其中执行必要的复制。

The most hackish way I could think of (and one you should never, ever use!) is through the use of the Marshal : 我能想到的最骇人听闻的方式(您永远都不会使用!)是使用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. 这实际上将保存在FooClass的数据FooStruct ,这允许将其从引用类型“投射”到值类型。

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: 如果使用FooStruct类型而不是泛型类型参数,则可以选择跳过第二个元帅,方法是将缓冲区直接从缓冲区转换为FooStruct类型:

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. 需要unsafe编译器选项,并且永远也不会在任何类型的生产环境中完成-这是非常缓慢的,不可预测。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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