C#将结构体转换为另一个结构体

7
有没有办法将这个转换为其他格式:
namespace Library
{
    public struct Content
    {
        int a;
        int b;
    }
}

我在Library2.Content中有一个结构体,其数据定义方式相同({ int a; int b; }),但方法不同。

是否有一种方法可以将来自Library.Content的结构体实例转换为Library2.Content?类似于:

Library.Content c1 = new Library.Content(10, 11);
Library2.Content c2 = (Libary2.Content)(c1); //this doesn't work
4个回答

13

你有几个选项,包括:

  • 你可以定义一个显式(或隐式)转换操作符将一种类型转换为另一种类型。需要注意的是,这意味着一个库(定义转换操作符的那个库)必须依赖于另一个库。
  • 你可以定义自己的实用方法(可能是扩展方法),将其中一种类型转换为另一种类型。在这种情况下,将代码转换为调用实用方法,而不是执行强制转换。
  • 你可以只需创建一个Library2.Content并将Library.Content的值传递给构造函数。

如果您无法访问构造函数或其他某些类型,该怎么办?这是我创建单元测试所需的内容,但遗憾的是该库不允许我创建自己的结构实例。 - Darkgaze

10

为了完整起见,如果数据类型的布局相同,则可以通过编组来完成此操作。

static void Main(string[] args)
{

    foo1 s1 = new foo1();
    foo2 s2 = new foo2();
    s1.a = 1;
    s1.b = 2;

    s2.c = 3;
    s2.d = 4;

    object s3 = s1;
    s2 = CopyStruct<foo2>(ref s3);

}

static T CopyStruct<T>(ref object s1)
{
    GCHandle handle = GCHandle.Alloc(s1, GCHandleType.Pinned);
    T typedStruct = (T)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(T));
    handle.Free();
    return typedStruct;
}

struct foo1
{
    public int a;
    public int b;

    public void method1() { Console.WriteLine("foo1"); }
}

struct foo2
{
    public int c;
    public int d;

    public void method2() { Console.WriteLine("foo2"); }
}

5
同样地,如果您允许不安全的代码:foo2 s2 = *(foo2*)&s1; - C.Evenhuis
哈哈,我正要字面上写同样的东西 :) - nurchi
@C.Evenhuis 我做不到这个。收到消息:无法获取托管类型的地址、大小或声明指向托管类型的指针。我的 foo2 等于 foo1,而我没有访问 foo1 的权限,所以我想对该类型进行“不安全”的转换。 - Darkgaze
@Darkgaze 那个技巧只适用于结构体,而且如果你正在使用泛型,我认为你需要一个where T:unmanaged的限制条件。 - C.Evenhuis
问题在于它包含指向类的指针。 :-/ 是的,不是理想的情况。 - Darkgaze

5

您可以在Library2.Content内定义一个明确的转换运算符,如下所示:

// explicit Library.Content to Library2.Content conversion operator
public static explicit operator Content(Library.Content content) {
    return new Library2.Content {
       a = content.a,
       b = content.b
    };
}

问题在于,我无法访问Library2内部,在Library1中我也不知道Library2的存在。 - Perry
那么选择@Kent Boogaart的第二或第三个选项。 - Bertrand Marron

0
有点晚了。但如果结构匹配,我过去曾经使用过这个。
public static object CastTo(ref object obj, Type type)
{
    var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(type));
    try
    {
        Marshal.StructureToPtr(obj, ptr, false);
        return Marshal.PtrToStructure(ptr, type);
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

感谢 @avi_sweden 指出应该释放分配的内存。

我认为你需要释放AllocHGlobal分配的内存,否则你可能会有未管理的内存泄漏。 - avl_sweden

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接