结构体 |
C |
C++ |
C# |
结构体的基本语法
|
C 结构体的基本语法为:
// 定义结构体
struct StructureName{
dataType member1;
dataType member2;
// 其他成员
};
示例:
#include <stdio.h>
struct Person {
char name[50];
int age;
float height;
};
int main() {
// 声明结构体变量并初始化
struct Person person1 = {"Alice", 30, 173};
// 访问结构体成员
printf("Name: %s\n", person1.name);
printf("Age: %d\n", person1.age);
printf("Height: %.2f\n", person1.height);
// 修改结构体成员
person1.age = 27;
printf("Updated Age: %d\n", person1.age);
return 0;
}
🡮
Name: Alice
Age: 30
Height: 173.00
Updated Age: 27
|
C++ 结构体与类的功能类似,但默认成员权限为public 。除了包含 C 的结构体功能外,还支持构造函数、方法及其他面向对象的特征。
C++ 结构体的基本语法为:
struct StructureName{
dataType member1;
dataType member2;
// 其他成员
};
示例:
#include <iostream>
// 定义结构体
struct Person {
std::string name;
int age;
double height;
};
int main() {
// 定义结构体变量并初始化
Person person1 = { "Alice", 30,173 };
// 访问结构体成员
std::cout << "Name: " << person1.name << std::endl;
std::cout << "Age: " << person1.age << std::endl;
std::cout << "Height: " << person1.height << std::endl;
// 修改结构体成员
person1.age = 27;
std::cout << "Updated Age: " << person1.age << std::endl;
return 0;
}
🡮
Name: Alice
Age: 30
Height: 173
Updated Age: 27
|
在 C# 中,结构体(struct )是一种值类型数据结构,用于封装多个相关的数据。与类(class )不同,结构体存储于堆栈(stack),具有更高的性能,尤其在处理小型数据时。
C# 结构体使用struct 关键字定义,可以用包括字段、属性、方法、事件、索引器和构造函数等。由于结构体是值类型,赋值操作会复制值,而不是引用。
struct StructureName{
public Datatype Member1;
public Datatype Member2;
public StructureName(DataType member1, Datatype member2){
Member1 = member1;
Member2 = member2;
}
public void Display(){
Console.WriteLine($"Member1: {Member1}, Member2: {<Member2}");
}
}
示例:
using System;
struct Point
{
public int X;
public int Y;
// 带参数的构造函数
public Point(int x, int y)
{
X = x;
Y = y;
}
// 显示点的信息
public void Display()
{
Console.WriteLine($"Point: ({X},{Y})");
}
}
class Program
{
static void Main()
{
// 使用构造函数初始化结构体
Point p1=new Point(10,20);
// 逐一赋值初始化
Point p2;
p2.X = 30;
p2.Y = 40;
// 调用方法
p1.Display();
p2.Display();
}
}
🡮
Point: (10,20)
Point: (30,40)
|
结构体的声明和定义方式
|
可以在文件的全局作用域定义结构体,然后在需要的地方声明结构体变量。
#include <stdio.h>
struct Point {
int x;
int y;
};
int main() {
struct Point p1 = { 10,20 };
printf("x = %d; y = %d\n", p1.x, p1.y);
return 0;
}
如果结构体只在特定范围内使用,则可以直接在变量声明时定义。
声明结构体变量时初始化值。
#include <stdio.h>
int main() {
struct Point {
int x;
int y;
}point1 = { 5,10 }, point2 = {15,20};
printf("point1 = (%d, %d)\n", point1.x, point1.y);
printf("point2 = (%d, %d)\n", point2.x, point2.y);
return 0;
}
🡮
point1 = (5, 10)
point2 = (15, 20)
声明结构体变量后赋值。
#include <stdio.h>
int main() {
struct Point {
int x;
int y;
}point1, point2;
point1.x = 5;
point1.y = 10;
point2.x = 15;
point2.y = 20;
printf("point1 = (%d, %d)\n", point1.x, point1.y);
printf("point2 = (%d, %d)\n", point2.x, point2.y);
return 0;
}
🡮
point1 = (5, 10)
point2 = (15, 20)
|
可以在文件的全局作用域定义结构体,然后在需要的地方声明结构体变量。
#include <iostream>
#include <format>
struct Point {
int x;
int y;
};
int main() {
struct Point p1 = { 10,20 };
std::cout << std::format("x = {}; y = {}\n", p1.x, p1.y);
return 0;
}
如果结构体只在特定范围内使用,则可以直接在变量声明时定义。
声明结构体变量时初始化值。
#include <iostream>
#include <format>
int main() {
struct Point {
int x;
int y;
}point1 = { 5,10 }, point2 = { 15,20 };
std::cout << std::format("point1 = ({},{})\n", point1.x, point1.y);
std::cout << std::format("point2 = ({},{})\n", point2.x, point2.y);
return 0;
}
🡮
point1 = (5,10)
point2 = (15,20)
声明结构体变量后赋值。
#include <iostream>
#include <format>
int main() {
struct Point {
int x;
int y;
}point1, point2;
point1.x = 5;
point1.y = 10;
point2.x = 15;
point2.y = 20;
std::cout << std::format("point1 = ({},{})\n", point1.x, point1.y);
std::cout << std::format("point2 = ({},{})\n", point2.x, point2.y);
return 0;
}
🡮
point1 = (5,10)
point2 = (15,20)
|
|
结构体的初始化
|
#include <stdio.h>
struct MyStruct {
int id;
char name[50];
};
int main() {
// 声明并初始化(列表初始化)
struct MyStruct s1 = { 1, "Alice" };
printf("Id: %d, Name: %s\n", s1.id, s1.name);
// 声明后赋值(使用成员初始化)
struct MyStruct s2;
s2.id = 2;
snprintf(s2.name, sizeof(s2.name), "John Doe"); // strcpy(s2.name, "John Doe");
printf("Id: %d, Name: %s\n", s2.id, s2.name);
return 0;
}
🡮
Id: 1, Name: Alice
Id: 2, Name: John Doe
🤖 代码解释
snprintf 是一个用于将格式化的数据写入字符串数组的函数。其作用与printf 类似,但snprintf 不会直接输出到标准输出,而是将结果写入指定的字符数组,并确保不会超过数组的大小,避免缓冲区溢出,其函数原型为int snprintf(char *str, size_t size, const char *format, ...); 。参数str 指向字符数组的指针,结果将被写入到该数组中;size 为要写入的最大字符数(包括字符串的终止字符\0 )。如果数组的大小不足以容纳所有数据,snprintf 将确保不会超过此大小;format 为格式化字符串,类似于printf 的格式化方式,用于指定如何格式化后续的参数;... 为格式化字符串中指定的额外参数,类似于printf 中的参数。snprintf 返回写入字符数组的字符数(不包括终止符\0 )。如果返回值大于或等于size ,则表示结果被截断,输出的数据没有完全写入字符数组。
strcpy 是一个用于将一个字符串复制到另一个字符串的标准库函数,通常用于字符串的复制,但需要注意避免发生缓冲区溢出,其函数原型为char *strcpy(char *dest, const char *src); 。参数dest 为目标字符串指针,指向一个足够大的字符数组,存储复制后的字符串;src 源字符串指针,为复制的字符串。strcpy 返回dest ,即目标字符串的指针。
|
C++ 结构体和 C 类似,但支持更多的初始化方法,如构造函数。
#include <iostream>
#include <string>
#include <format>
struct MyStruct {
int id;
std::string name;
// 构造函数
MyStruct():id(0),name("Nobody"){} // 默认构造函数
MyStruct(int i,std::string n):id(i),name(n){} // 自定义构造函数
};
int main() {
// 使用构造函数初始化
MyStruct s1(1, "Alice");
// 列表初始化
MyStruct s2 = { 2,"John Doe" };
// 默认初始化后赋值(需要在结构体中配置默认构造函数)
MyStruct s3;
s3.id = 3;
s3.name = "Lily";
for (auto s : { s1,s2,s3 }) {
std::cout << std::format("Id: {}, Name: {}\n", s.id, s.name);
}
return 0;
}
🡮
Id: 1, Name: Alice
Id: 2, Name: John Doe
Id: 3, Name: Lily
🤖 代码解释
MyStruct():id(0),name("Nobody"){}
为定义的默认构造函数。这个构造函数没有参数;初始化列表id(0),name("Nobody") 用于初始化id 为0 和name 为Nobody 。当使用MyStruct 时未提供任何参数,如MyStruct s3; ,这个默认构造函数将被调用。
MyStruct(int i,std::string n):id(i),name(n){}
为定义的构造函数。这个构造函数接受两个参数,int i 和std::string n 。初始化列表id(i),name(n) 用于将传入的参数i 和n 分别赋值给id 和name 成员变量。当创建MyStruct 对象时提供有具体参数,例如MyStruct s1(1, "Alice"); ,这个构造函数将被调用。
|
在 C# 中,结构体(struct )默认是值类型(value type),并且编译器会自动生成一个默认构造函数。这个默认构造函数会将所有字段初始化为其默认值,如int 类型初始化为0 ,string 类型初始化为null 等。C# 不允许显示定义无参数的默认构造函数(从 C# 10开始例外,但仅适用于 .NET6 或更高版本)。
using System;
struct MyStruct
{
public int Id;
public string Name;
// 构造函数
public MyStruct(int id, string name)
{
Id = id;
Name = name;
}
}
class Program
{
static void Main()
{
// 使用构造函数初始化
MyStruct s1=new MyStruct(1, "Alice");
// 声明后对字段赋值初始化
MyStruct s2;
s2.Id = 2;
s2.Name = "John Doe";
// 对字段使用默认值。调用自动生成的默认构造函数
MyStruct s3 = new MyStruct();
Console.WriteLine($"Id: {s1.Id}, Name: {s1.Name}");
Console.WriteLine($"Id: {s2.Id}, Name: {s2.Name}");
Console.WriteLine($"Id: {s3.Id}, Name: {s3.Name}");
Console.WriteLine($"Id: {s3.Id}, Name: {s3.Name ?? "Nobody"}");
}
}
🡮
Id: 1, Name: Alice
Id: 2, Name: John Doe
Id: 0, Name:
Id: 0, Name: Nobody
定义无参数(默认)构造函数
using System;
struct MyStruct
{
public int Id;
public string Name;
// 显示定义无参数构造函数
public MyStruct()
{
Id = -1;
Name = "Unknown";
}
public MyStruct(int id, string name)
{
Id = id;
Name = name;
}
}
class Program
{
static void Main()
{
MyStruct s1=new MyStruct(1, "Alice");
MyStruct s2;
s2.Id = 2;
s2.Name = "John Doe";
MyStruct s3 = new MyStruct(); // 调用显示定义的无参数构造函数
Console.WriteLine($"Id: {s1.Id}, Name: {s1.Name}");
Console.WriteLine($"Id: {s2.Id}, Name: {s2.Name}");
Console.WriteLine($"Id: {s3.Id}, Name: {s3.Name}");
Console.WriteLine($"Id: {s3.Id}, Name: {s3.Name ?? "Nobody"}");
}
}
🡮
Id: 1, Name: Alice
Id: 2, Name: John Doe
Id: -1, Name: Unknown
Id: -1, Name: Unknown
🤖 代码解释
Console.WriteLine($"Id: {s3.Id}, Name: {s3.Name ?? "Nobody"}");
?? 为空合并运算符(Null-Coalescing Operator),如果s3.Name 为null ,运算结果将为Nobody ;如不不为null ,运算结果将为s3.Name 的默认值。
|
访问结构体
C、C++ 和 C# 访问结构体成员方式略有不同,如表,
特性 |
C |
C++ |
C# |
成员访问操作符 |
. 和-> |
. 和-> |
. |
是否支持方法 |
否 |
是 |
是 |
是否支持构造函数 |
否 |
是 |
是 |
是否支持指针 |
是 |
是 |
否(除非启用不安全代码) |
默认权限 |
无 |
public |
public |
|
如果为结构体变量,可以用. 访问其成员,如rect.width ;如果为结构体指针,需要用-> 来间接访问其成员,如ptr->width 。
#include <stdio.h>
// 定义结构体
struct Rectangle {
int width;
int height;
};
int main() {
struct Rectangle rect = { 10,20 }; // 声明并初始化结构体变量
struct Rectangle* ptr = ▭ // 定义指向结构体的指针
// 使用`.`访问结构体成员
printf("Width: %d, Height: %d\n", rect.width, rect.height);
// 使用`->`通过指针访问结构体成员
printf("Width: %d, Height: %d\n", ptr->width, ptr->height);
return 0;
}
🡮
Width: 10, Height: 20
Width: 10, Height: 20
|
如果为结构体变量,可以用. 访问其成员,如rect.width (成员变量)和rect.display() (成员函数);如果为结构体指针,需要用-> 来间接访问其成员,如ptr->width (成员变量)和ptr->display() (成员函数)。
#include <iostream>
#include <format>
// 定义结构体
struct Rectangle {
int width;
int height;
// 构造函数
Rectangle(int w, int h):width(w),height(h){}
// 成员函数
void display() {
std::cout << std::format("Width: {}; Height: {}\n", width, height);
}
};
int main() {
Rectangle rect(10, 20); // 调用构造函数创建结构体
Rectangle* ptr = ▭ // 定义指向结构体的指针
// 使用`.`访问成员方法
rect.display();
// 使用`->`通过指针访问成员方法
ptr->display();
// 使用`.`访问成员变量
std::cout << std::format("Width: {}, Height: {}\n", rect.width, rect.height);
// 使用`->`通过指针访问成员变量
std::cout << std::format("Width: {}, Height: {}\n", ptr->width, ptr->height);
return 0;
}
🡮
Width: 10; Height: 20
Width: 10; Height: 20
Width: 10, Height: 20
Width: 10, Height: 20
|
C# 结构体为值类型,不能像 C/C++ 直接使用指针(除非启用不安全代码),其成员访问同一使用. 操作符。
using System;
struct Rectangle
{
public int Width;
public int Height;
// 构造函数
public Rectangle(int width,int height)
{
Width = width;
Height = height;
}
// 成员方法
public void Display()
{
Console.WriteLine($"Width: {Width}, Height: {Height}");
}
}
class Program
{
static void Main()
{
Rectangle rect = new Rectangle(10,20); // 创建结构体实例
// 使用`.`访问成员方法
rect.Display();
// 使用`.`访问成员变量
Console.WriteLine($"Width: {rect.Width}, Height: {rect.Height}");
}
}
🡮
Width: 10, Height: 20
Width: 10, Height: 20
|
结构体数组
|
在 C 中,结构体数组是由结构体类型的多个实例组成的数组。通过下标访问数组中的结构体元素,然后用. 或-> 访问结构体成员。
#include <stdio.h>
// 定义结构体
struct Point {
int x;
int y;
};
int main() {
// 定于结构体数组并初始化
struct Point points[3] = {
{1,2},
{3,4},
{5,6}
};
// 遍历结构体数组
for (int i = 0;i < 3;i++) {
printf("Point %d: x = %d, y = %d\n", i + 1, points[i].x, points[i].y);
}
return 0;
}
🡮
Point 1: x = 1, y = 2
Point 2: x = 3, y = 4
Point 3: x = 5, y = 6
|
C++ 的结构体数组与 C 基本相同,但可以使用 C++ 的特性,如果构造函数和方法,通过初始化列表来赋值。
#include <iostream>
#include <format>
// 定义结构体
struct Point {
int x;
int y;
// 构造函数
Point(int a=0,int b=0):x(a),y(b){}
// 成员函数
void display()const {
std::cout << std::format("X = {}, y = {}\n", x, y);
}
};
int main() {
// 定义结构体数组并初始化
Point points[3] = { {1,2},{3,4},{5,6} };
// 遍历结构体数组
for (int i = 0;i < 3;i++) {
std::cout << std::format("Point {}: ", i + 1);
points[i].display();
}
return 0;
}
🡮
Point 1: X = 1, y = 2
Point 2: X = 3, y = 4
Point 3: X = 5, y = 6
|
C# 中,结构体数组中的每个元素是结构体的一个实例。
using System;
// 定义结构体
struct Point
{
public int X;
public int Y;
// 构造函数
public Point(int x, int y)
{
X = x; Y = y;
}
// 成员方法
public void Display()
{
Console.WriteLine($"X = {X}, Y = {Y}");
}
}
class Program
{
static void Main()
{
// 定义结构体数组并初始化
Point[] points = new Point[3]{
new Point(1,2),
new Point(3,4),
new Point(4,5)
};
// 遍历结构体数组
for (int i = 0; i < points.Length; i++)
{
Console.Write($"Point {i + 1}: ");
points[i].Display();
}
}
}
🡮
Point 1: X = 1, Y = 2
Point 2: X = 3, Y = 4
Point 3: X = 4, Y = 5
|
结构体嵌套
在 C、C++ 和 C# 中,结构体可以嵌套,即在一个结构体内部定义另一个结构体。
|
示例中struct Address 被嵌套在struct Person 中,可以使用person.address.street 和ptr->address.city 访问嵌套结构体的成员。
#include <stdio.h>
// 定义嵌套结构体
struct Address {
char street[100];
char city[50];
};
struct Person {
char name[50];
int age;
struct Address address; // 嵌套结构体
};
int main() {
// 初始化嵌套结构体
struct Person person = { "John Doe",25,{"Burma Rd", "New York"} };
struct Person *ptr = &person;
// 访问嵌套结构体,用`.`或`->`操作符
printf("Name: %s\n", person.name);
printf("Age: %d\n", ptr->age);
printf("Street: %s\n", person.address.street);
printf("City: %s\n", ptr->address.city);
return 0;
}
🡮
Name: John Doe
Age: 25
Street: Burma Rd
City: New York
|
C++ 嵌套结构体与 C 类似,示例中struct Address 被嵌套在struct Person 中,可以使用person.address.street 和ptr->address.city 访问嵌套结构体的成员。
#include <iostream>
#include <format>
struct Address {
std::string street;
std::string city;
Address(std::string s, std::string c):street(s),city(c){}
};
struct Person {
std::string name;
int age;
Address address;
void display() const {
std::cout << std::format("Name: {}\n", name);
std::cout << std::format("Age: {}\n", age);
std::cout << std::format("Street: {}\n", address.street);
std::cout << std::format("City: {}\n", address.city);
}
};
int main() {
Address addr("Burma Rd", "New York");
Person person("John Doe", 25, addr);
Person* ptr = &person;
person.display();
std::cout << std::format("Street: {}\n", person.address.street);
std::cout << std::format("City: {}\n", ptr->address.city);
return 0;
}
🡮
Name: John Doe
Age: 25
Street: Burma Rd
City: New York
Street: Burma Rd
City: New York
|
示例中struct Address 被嵌套在struct Person 中,可以使用person.Address.Street 访问嵌套结构体的成员。
using System;
using System.Net.Sockets;
struct Address
{
public string Street;
public string City;
public Address(string street, string city)
{
Street = street;
City = city;
}
}
struct Person
{
public string Name;
public int Age;
public Address Address;
public Person(string name, int age, Address address)
{
Name = name;
Age = age;
Address = address;
}
public void Display()
{
Console.WriteLine($"Name: {Name}");
Console.WriteLine($"Age: {Age}");
Console.WriteLine($"Street: {Address.Street}");
Console.WriteLine($"City: {Address.City}");
}
}
class Program
{
static void Main()
{
Address address = new Address("Burma Rd","New York");
Person person = new Person("John Doe", 25, address);
person.Display();
Console.WriteLine($"Street: {person.Address.Street}");
}
}
🡮
Name: John Doe
Age: 25
Street: Burma Rd
City: New York
Street: Burma Rd
|
结构体作为函数参数和返回值
特性 |
C |
C++ |
C# |
参数传递 |
按值、按指针 |
按值、按引用(& )、按指针 |
按值、按引用(ref )、按输出(out ) |
返回值 |
返回副本 |
返回副本、引用、指针 |
返回副本、支持out 关键字 |
|
C 中的结构体可以按值传递(将整个结构体赋值一份传递给函数)和按指针传递(传递结构体的地址,函数可以直接操作原始数据)。
#include <stdio.h>
// 定义结构体
struct Point {
int x;
int y;
};
// 按值传递
void printPointByValue(struct Point p) {
printf("Point by value: (%d, %d)\n", p.x, p.y);
}
// 按指针传递
void modifyPointByPointer(struct Point* p) {
p->x = 100; // 修改原始数据
p->y = 200;
}
int main() {
struct Point p1 = { 10,20 };
// 按值传递
printPointByValue(p1);
// 按指针传递
modifyPointByPointer(&p1);
printf("Point after modify: (%d,%d)", p1.x, p1.y);
return 0;
}
🡮
Point by value: (10, 20)
Point after modify: (100,200)
C 中可以直接返回一个结构体值,但返回值通常是结构体的副本。
#include <stdio.h>
// 定义结构体
struct Point {
int x;
int y;
};
// 返回结构体
struct Point createPoint(int x, int y) {
struct Point p = { x,y };
return p; // 返回结构体副本
}
int main() {
struct Point p1 = createPoint(10, 20);
printf("Created Point: (%d, %d)\n", p1.x, p1.y);
return 0;
}
🡮
Created Point: (10, 20)
|
C++ 中的结构体作为参数传递包括按值传递(传递副本);按引用传递(使用引用& 避开副本开销,并允许修改原始数据);按指针传递,与 C 类似(传递结构体的地址,函数可以直接操作原始数据)。
#include <iostream>
#include <format>
// 定义结构体
struct Point {
int x;
int y;
// 构造函数
Point(int x_val, int y_val):x(x_val),y(y_val){}
};
// 按值传递
void printPoint(Point p) {
std::cout << std::format("Point by value: ({}, {})\n", p.x, p.y);
}
// 按引用传递
void modifyPointByRef(Point& p) {
p.x = 100;
p.y = 200;
}
// 按指针传递
void modifyPointByPointer(Point* p) {
p->x = 300;
p->y = 400;
}
int main() {
Point p1(10, 20);
// 按值传递
printPoint(p1);
// 按引用传递
modifyPointByRef(p1);
std::cout << std::format("After modify by reference: ({}, {})\n", p1.x, p1.y);
// 按指针传递
modifyPointByPointer(&p1);
std::cout << std::format("After modify by pointer: ({}, {})\n", p1.x, p1.y);
return 0;
}
🡮
Point by value: (10, 20)
After modify by reference: (100, 200)
After modify by pointer: (300, 400)
C++ 允许直接返回结构体值,也可以返回引用或指针。
#include <iostream>
#include <format>
struct Point {
int x;
int y;
Point(int x_val, int y_val):x(x_val),y(y_val){}
};
// 返回结构体
Point createPoint(int x, int y) {
return Point(x, y); // 返回副本
}
// 返回引用(不推荐局部遍历引用)
Point& riskyReferenceReturn() {
static Point p(0, 0); // 静态变量
return p;
}
int main() {
Point p1 = createPoint(10, 20);
std::cout << std::format("Created Point: ({}, {})\n", p1.x, p1.y);
Point p2 = riskyReferenceReturn();
std::cout << std::format("Risky reference Point: ({}, {})\n", p2.x, p2.y);
return 0;
}
🡮
Created Point: (10, 20)
Risky reference Point: (0, 0)
|
C# 结构体作为参数传递包括按值传递(传递副本,原始数据不会被修改);按引用传递(通过ref 关键字传递引用,允许修改原始数据);按输出传递(使用out 关键字返回计算后的值)。
using System;
struct Point
{
public int X;
public int Y;
public Point(int x, int y) {
X= x;
Y = y;
}
}
class Program
{
static void Main()
{
Point p1=new Point(10,20);
PrintPoint(p1);
ModifyPoint(ref p1);
Console.WriteLine($"After modify by ref: ({p1.X}, {p1.Y})");
Point result;
createPointByOut(out result, 30, 50);
Console.WriteLine($"Result: ({result.X}, {result.Y})");
}
// 按值传递
static void PrintPoint(Point p)
{
Console.WriteLine($"Point by value: ({p.X}, {p.Y})");
}
// 按引用传递
static void ModifyPoint(ref Point p)
{
p.X = 100;
p.Y = 200;
}
// 按输出 out 关键字传递
static void createPointByOut(out Point p, int x, int y)
{
p = new Point(x, y);
}
}
🡮
Point by value: (10, 20)
After modify by ref: (100, 200)
Result: (30, 50)
C# 支持返回结构体值,并可通过out 参数返回多个值。
using System;
struct Point
{
public int X;
public int Y;
public Point(int x, int y) {
X= x;
Y = y;
}
}
class Program
{
static void Main()
{
Point p1 = CreatePoint(10, 20);
Console.WriteLine($"Created Point: ({p1.X}, {p1.Y})");
}
static Point CreatePoint(int x, int y)
{
return new Point(x, y);
}
}
🡮
Created Point: (10, 20)
|
[C#] 结构体与接口
|
|
|
C# 中,结构体可以实现接口(interface ),允许为值类型定义行为,并保持其轻量级的特性;结构体可以实现一个或多个接口,并需要为接口中定义的所有成员提供实现;当将一个结构体赋值给接口变量时,会发生装箱(boxing),导致性能开销。为了避免装箱,可以使用泛型约束(where T : IShape )避免装箱。
using System;
interface IShape
{
double GetArea();
void Display()=>Console.WriteLine("Default Display Implementation!");
}
struct Rectangle : IShape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width; Height = height;
}
// 实现接口方法
public double GetArea()
{
return Width * Height;
}
public void Display()
{
Console.WriteLine($"Rectangle: Width = {Width}, Height = {Height}, Area = {GetArea()}");
}
}
class Program
{
static void Main()
{
// 使用结构体
Rectangle rectangle = new Rectangle(10,20);
rectangle.Display();
// 将结构体赋值给接口
IShape shape = rectangle;
shape.Display(); // 掉用接口的方法
DisplayShape(shape); // 使用泛型约束,避免装箱
Console.WriteLine($"Area via interface: {shape.GetArea()}");
}
static void DisplayShape<T>(T shape) where T : IShape
{
shape.Display();
}
}
🡮
Rectangle: Width = 10, Height = 20, Area = 200
Rectangle: Width = 10, Height = 20, Area = 200
Rectangle: Width = 10, Height = 20, Area = 200
Area via interface: 200
🤖 代码解释
static void DisplayShape<T>(T shape) where T : IShape
{
shape.Display();
}
static 表示该方法是静态方法,不依赖于类的实例,可以直接通过类名调用。
void 为方法的返回类型,表示此方法不返回任何值。
DisplayShape<T> 是泛型方法定义,<T> 表示该方法是一个泛型方法,可以接收任何类型的参数,但前提是该类型满足后续的约束条件。
(T shape) 是方法参数,T 是类型参数,表示调用方法时传入的具体类型。shape 是参数名,表示传入该方法的实际对象。
where T : IShape 为泛型约束。where T : IShape 限制了类型参数T ,表示T 必须实现接口IShape 。这样,shape 就可以安全地调用IShape 接口中的成员,例如Display() 方法。
shape.Display(); 中,shape 是传入的泛型类型参数,一个实现了IShape 接口的对象。通过IShape 接口调用其定义的Display 方法。因为类型参数T 被约束为实现了IShape ,所以编译器知道T 类型中肯定有Display() 方法。
|