C#中struct里面定义数组问题

时间:2022-08-30 20:00:30
public struct sTest
{  
  public int id; 
  public string s;
  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]   
  public int[] test;
}
在c#中struct里面定义数组,为什么要加类似 [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] 这行东西呢。
看资料说因为struct是值类型,而数组是引用类型,所以出现这些麻烦。
不过,string不也是引用类型吗,为什么用起来又没啥特别?

9 个解决方案

#1


另外网上找到用unsafe的写法

public unsafe fixed int test[6];   

这个和

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]   
  public int[] test;

的写法,两者的比较是怎样的?
请大家指点~~

#2


结构里使用数组不需要你定义[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)],我给个例子给你看看:

    class Program
    {
        static void Main(string[] args)
        {
            StructTest structTest = new StructTest();

            structTest.PointX = 20;
            structTest.PointY = 30;
            structTest.SizePoint = new int[] { 3, 6, 27, 48 };

            Console.WriteLine("PointX = {0}, PointY = {1}", structTest.PointX, structTest.PointY);
            Console.WriteLine("SizePoint array has {0} element, Now output:\r", structTest.SizePoint.Length);

            foreach (int x in structTest.SizePoint)
            {
                Console.WriteLine(x.ToString());
            }

            Console.ReadLine();
        }
    }


    struct StructTest
    {
        public int PointX;
        public int PointY;
        public int[] SizePoint;
    }

#3


你再看看MSDN里结构的描述,也没有说不能用数组的:

结构是使用 struct 关键字定义的,例如: 

public struct PostalAddress
  {
      // Fields, properties, methods and events go here...
  
  }
  
public struct PostalAddress
{
    // Fields, properties, methods and events go here...
}


结构与类共享大多数相同的语法,但结构比类受到的限制更多: 

在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。

结构不能声明默认构造函数(没有参数的构造函数)或析构函数。

结构在赋值时进行复制。将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。在使用值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。

结构是值类型,而类是引用类型。 

与类不同,结构的实例化可以不使用 new 运算符。

结构可以声明带参数的构造函数。

一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object。 

结构可以实现接口。

结构可用作可以为 null 的类型,因而可向其赋 null 值。

#4


但是如果要在struct里面指定数组大小,就只能按前面的方法做吧

#5



// 如果要定义的时候指定大小,为什么不直接new呢?
public struct sTest
{   
    public int id; 
    public string s;
    public int[] test = new int[6] { 0 };
}

#6


这是调用非托管程序的需要

#7


其实,char  str[128];这种C/C++的风格,映射到C#时,也要指定数组长度大小!
而char* str,因为是字符指针,是变长的,在结构体只占4个字节,string是引用类,也是4个字节,刚好对齐。

要解释数组为什么一定要指定大小,你可以从C++角度去想:
int  ary[2];

如果换成是C#:
int[2]  ary;

你编译一下,编译器马上报错!
由于两边的编译器不一样,产生两边的语法不一样,这是很正常的!

不知道这样解释你清楚没有?

#8


引用 6 楼 hdt 的回复:
这是调用非托管程序的需要
+

#9


去学VB.NET吧,据说VB.NET中简单多了,根本不需要注明这么多,它都是智能感知的。(我认为很不严谨)

你这边和引用类型无关,如果不需要传递给C++这类非托管dll调用,就根本不需要添加MarshalAs的声明,那个是将对象地址固定用的,不然动态的地址是无法传递给非托管dll调用的。

#1


另外网上找到用unsafe的写法

public unsafe fixed int test[6];   

这个和

  [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)]   
  public int[] test;

的写法,两者的比较是怎样的?
请大家指点~~

#2


结构里使用数组不需要你定义[MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)],我给个例子给你看看:

    class Program
    {
        static void Main(string[] args)
        {
            StructTest structTest = new StructTest();

            structTest.PointX = 20;
            structTest.PointY = 30;
            structTest.SizePoint = new int[] { 3, 6, 27, 48 };

            Console.WriteLine("PointX = {0}, PointY = {1}", structTest.PointX, structTest.PointY);
            Console.WriteLine("SizePoint array has {0} element, Now output:\r", structTest.SizePoint.Length);

            foreach (int x in structTest.SizePoint)
            {
                Console.WriteLine(x.ToString());
            }

            Console.ReadLine();
        }
    }


    struct StructTest
    {
        public int PointX;
        public int PointY;
        public int[] SizePoint;
    }

#3


你再看看MSDN里结构的描述,也没有说不能用数组的:

结构是使用 struct 关键字定义的,例如: 

public struct PostalAddress
  {
      // Fields, properties, methods and events go here...
  
  }
  
public struct PostalAddress
{
    // Fields, properties, methods and events go here...
}


结构与类共享大多数相同的语法,但结构比类受到的限制更多: 

在结构声明中,除非字段被声明为 const 或 static,否则无法初始化。

结构不能声明默认构造函数(没有参数的构造函数)或析构函数。

结构在赋值时进行复制。将结构赋值给新变量时,将复制所有数据,并且对新副本所做的任何修改不会更改原始副本的数据。在使用值类型的集合(如 Dictionary<string, myStruct>)时,请务必记住这一点。

结构是值类型,而类是引用类型。 

与类不同,结构的实例化可以不使用 new 运算符。

结构可以声明带参数的构造函数。

一个结构不能从另一个结构或类继承,而且不能作为一个类的基。所有结构都直接继承自 System.ValueType,后者继承自 System.Object。 

结构可以实现接口。

结构可用作可以为 null 的类型,因而可向其赋 null 值。

#4


但是如果要在struct里面指定数组大小,就只能按前面的方法做吧

#5



// 如果要定义的时候指定大小,为什么不直接new呢?
public struct sTest
{   
    public int id; 
    public string s;
    public int[] test = new int[6] { 0 };
}

#6


这是调用非托管程序的需要

#7


其实,char  str[128];这种C/C++的风格,映射到C#时,也要指定数组长度大小!
而char* str,因为是字符指针,是变长的,在结构体只占4个字节,string是引用类,也是4个字节,刚好对齐。

要解释数组为什么一定要指定大小,你可以从C++角度去想:
int  ary[2];

如果换成是C#:
int[2]  ary;

你编译一下,编译器马上报错!
由于两边的编译器不一样,产生两边的语法不一样,这是很正常的!

不知道这样解释你清楚没有?

#8


引用 6 楼 hdt 的回复:
这是调用非托管程序的需要
+

#9


去学VB.NET吧,据说VB.NET中简单多了,根本不需要注明这么多,它都是智能感知的。(我认为很不严谨)

你这边和引用类型无关,如果不需要传递给C++这类非托管dll调用,就根本不需要添加MarshalAs的声明,那个是将对象地址固定用的,不然动态的地址是无法传递给非托管dll调用的。