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

时间:2015-01-14 10:13:16

标签: c# inheritance struct interface casting

与同事讨论是否有任何方法可以将结构强制转换为类我们尝试过的示例

 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; }
        }
    }
}

但是我们得到了一个无效的演员例外:D
是否有任何棘手的方法来提取接口并将其分配给类,因为接口是引用类型,类是引用类型,类实现接口

3 个答案:

答案 0 :(得分:3)

您不能通过接口直接在两者之间进行转换,因为它们不直接相关(即继承),所以不允许这样做。

编译器可以捕获很多这类东西,甚至不允许转换编译。如果编译器无法执行此操作,则运行时会执行此操作。对于显式转换,运行时将在失败的转换上抛出异常,对于隐式转换的尝试(仅限引用类型),运行时返回null并且不会引发异常。

类型检查实际上会检查FooStruct FooClass,但它不可能。

但是,您可以使用强制转换运算符在它们之间进行转换,使其看起来像一样

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; }
}

不要将演员与转换混淆。另外,要小心将接口应用于struct类型,因为可以进行装箱。

答案 1 :(得分:1)

没有。

FooClass创建一个复制方法,该方法采用IFoo的实例,并在那里执行必要的复制。

答案 2 :(得分:1)

我能想到的最 hackish 方式(以及你永远不应该使用的方式!)是通过使用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));
}

这实际上将FooClass中保存的数据整理到FooStruct,这样就可以将其保存为#34;从引用类型到值类型。

如果您使用FooStruct类型而不是泛型类型参数,则可以选择跳过第二个marshal,方法是直接从缓冲区将缓冲区转换为FooStruct类型:

fixed (byte* b = buffer)
{
    var s = (FooStruct*) b;
    return *s;
}

需要unsafe编译器选项,从不 永远在任何类型的生产环境中完成 - 它非常慢且不可预测。< / p>