news 2026/8/5 20:14:44

003010003_WPF Border 基类官方类定义逐行深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
003010003_WPF Border 基类官方类定义逐行深度解析

003010003_WPF Border 基类官方类定义逐行深度解析

摘要:本文基于 .NET 8 官方源码,对 WPFBorder类进行逐行深度解析,涵盖类层次结构、完整类定义、静态构造函数中的依赖属性注册、五大核心属性(Background / BorderBrush / BorderThickness / CornerRadius / Padding)、受保护方法(MeasureOverride / ArrangeOverride / OnRender / GetLayoutClip)、核心工作原理(测量→排列→渲染),以及工业上位机中的典型应用实例与最佳实践,帮助开发者全面掌握 Border 的底层机制与实战技巧。


一、Border 在 WPF 类层次结构中的位置

plaintext:

System.Object ↳ System.Windows.Threading.DispatcherObject ↳ System.Windows.DependencyObject ↳ System.Windows.Media.Visual ↳ System.Windows.UIElement ↳ System.Windows.FrameworkElement ↳ System.Windows.Controls.Decorator ← 所有装饰器控件的基类 ↳ System.Windows.Controls.Border ← 我们今天的主角

核心设计意义

  • 继承自Decorator:只能包含一个子元素,专门用于装饰其他控件
  • 实现了完整的视觉装饰能力:背景、边框、圆角、内边距
  • 自动裁剪子元素到圆角区域:解决了子元素超出圆角的问题
  • 轻量级高性能:没有复杂的逻辑,渲染效率极高

二、完整官方类定义(.NET 8 源码级)

csharp:

using System.Windows.Automation.Peers; using System.Windows.Media; using System.Windows.Markup; namespace System.Windows.Controls { /// <summary> /// 表示一个可以在另一个元素周围绘制边框、背景和圆角的装饰器控件 /// </summary> /// <remarks> /// Border 只能包含一个子元素。如果需要装饰多个元素,请将它们放在一个布局容器中, /// 然后将该容器作为 Border 的子元素。 /// </remarks> [ContentProperty("Child")] [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] public class Border : Decorator { // ============================================== // 依赖属性定义 // ============================================== public static readonly DependencyProperty BackgroundProperty; public static readonly DependencyProperty BorderBrushProperty; public static readonly DependencyProperty BorderThicknessProperty; public static readonly DependencyProperty CornerRadiusProperty; public static readonly DependencyProperty PaddingProperty; public static readonly DependencyProperty ClipToBoundsProperty; // ============================================== // 静态构造函数 // ============================================== static Border() { // 注册依赖属性 BackgroundProperty = DependencyProperty.Register( nameof(Background), typeof(Brush), typeof(Border), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender), new ValidateValueCallback(IsValidBrush)); BorderBrushProperty = DependencyProperty.Register( nameof(BorderBrush), typeof(Brush), typeof(Border), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender), new ValidateValueCallback(IsValidBrush)); BorderThicknessProperty = DependencyProperty.Register( nameof(BorderThickness), typeof(Thickness), typeof(Border), new FrameworkPropertyMetadata( new Thickness(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender), new ValidateValueCallback(IsValidThickness)); CornerRadiusProperty = DependencyProperty.Register( nameof(CornerRadius), typeof(CornerRadius), typeof(Border), new FrameworkPropertyMetadata( new CornerRadius(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender), new ValidateValueCallback(IsValidCornerRadius)); PaddingProperty = DependencyProperty.Register( nameof(Padding), typeof(Thickness), typeof(Border), new FrameworkPropertyMetadata( new Thickness(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange), new ValidateValueCallback(IsValidThickness)); ClipToBoundsProperty = DependencyProperty.Register( nameof(ClipToBounds), typeof(bool), typeof(Border), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender)); // 重写默认样式键 DefaultStyleKeyProperty.OverrideMetadata( typeof(Border), new FrameworkPropertyMetadata(typeof(Border))); } // ============================================== // 公共构造函数 // ============================================== public Border(); // ============================================== // 公共属性 // ============================================== [Bindable(true)] [Category("Appearance")] public Brush Background { get; set; } [Bindable(true)] [Category("Appearance")] public Brush BorderBrush { get; set; } [Bindable(true)] [Category("Appearance")] public Thickness BorderThickness { get; set; } [Bindable(true)] [Category("Appearance")] public CornerRadius CornerRadius { get; set; } [Bindable(true)] [Category("Layout")] public Thickness Padding { get; set; } [Bindable(true)] [Category("Appearance")] public bool ClipToBounds { get; set; } // ============================================== // 受保护方法 // ============================================== protected override AutomationPeer OnCreateAutomationPeer(); protected override void OnRender(DrawingContext drawingContext); protected override Size MeasureOverride(Size constraint); protected override Size ArrangeOverride(Size finalSize); protected override Geometry GetLayoutClip(Size layoutSlotSize); } }

三、类级特性逐行解析

1.[ContentProperty("Child")]

C#:

[ContentProperty("Child")]
  • 作用:指定控件的默认内容属性
  • 设计意图:允许在 XAML 中直接编写子元素,而不需要显式指定Child属性名
  • 核心意义:这就是为什么我们可以写<Border><Button/></Border>而不是<Border Child="{StaticResource MyButton}"/>的原因
  • 工业场景价值:极大简化了 XAML 代码,提高了开发效率

2.[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]

C#:

[Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)]
  • 作用:本地化特性,告诉本地化工具该类不需要本地化。
  • 设计意图:Border 是纯视觉装饰控件,没有需要本地化的文本内容。

四、静态构造函数解析(核心初始化逻辑)

静态构造函数是 Border 最关键的部分,负责所有核心依赖属性的注册。我将按功能分组解析每个属性的注册细节。

1.BackgroundProperty注册

csharp:

BackgroundProperty = DependencyProperty.Register( nameof(Background), typeof(Brush), typeof(Border), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender), new ValidateValueCallback(IsValidBrush));
  • 类型Brush

  • 默认值Brushes.Transparent(透明)

  • 元数据标志

    • AffectsRender:属性变化会影响渲染
    • SubPropertiesDoNotAffectRender:画刷的子属性变化不会影响渲染(优化性能)
  • 验证回调IsValidBrush,确保画刷不为 null

2.BorderBrushProperty注册

csharp:

BorderBrushProperty = DependencyProperty.Register( nameof(BorderBrush), typeof(Brush), typeof(Border), new FrameworkPropertyMetadata( Brushes.Transparent, FrameworkPropertyMetadataOptions.AffectsRender | FrameworkPropertyMetadataOptions.SubPropertiesDoNotAffectRender), new ValidateValueCallback(IsValidBrush));
  • 类型Brush
  • 默认值Brushes.Transparent(透明)
  • 元数据标志:与 Background 相同
  • 验证回调IsValidBrush

3.BorderThicknessProperty注册

csharp:

BorderThicknessProperty = DependencyProperty.Register( nameof(BorderThickness), typeof(Thickness), typeof(Border), new FrameworkPropertyMetadata( new Thickness(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender), new ValidateValueCallback(IsValidThickness));
  • 类型Thickness

  • 默认值new Thickness(0)(无边框)

  • 元数据标志

    • AffectsMeasure:影响测量
    • AffectsArrange:影响排列
    • AffectsRender:影响渲染
  • 验证回调IsValidThickness,确保厚度值非负

4.CornerRadiusProperty注册(最常用)

csharp:

CornerRadiusProperty = DependencyProperty.Register( nameof(CornerRadius), typeof(CornerRadius), typeof(Border), new FrameworkPropertyMetadata( new CornerRadius(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange | FrameworkPropertyMetadataOptions.AffectsRender), new ValidateValueCallback(IsValidCornerRadius));
  • 类型CornerRadius
  • 默认值new CornerRadius(0)(直角)
  • 元数据标志:与 BorderThickness 相同
  • 验证回调IsValidCornerRadius,确保圆角半径非负
  • 核心设计意义:实现圆角效果,这是 Border 最受欢迎的特性

5.PaddingProperty注册

csharp:

PaddingProperty = DependencyProperty.Register( nameof(Padding), typeof(Thickness), typeof(Border), new FrameworkPropertyMetadata( new Thickness(0), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange), new ValidateValueCallback(IsValidThickness));
  • 类型Thickness
  • 默认值new Thickness(0)(无内边距)
  • 元数据标志AffectsMeasureAffectsArrange(不影响渲染)
  • 验证回调IsValidThickness

6.ClipToBoundsProperty注册

csharp:

ClipToBoundsProperty = DependencyProperty.Register( nameof(ClipToBounds), typeof(bool), typeof(Border), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.AffectsRender));
  • 类型bool
  • 默认值false
  • 元数据标志AffectsRender
  • 核心作用:控制是否裁剪超出 Border 边界的子元素内容
  • 重要特性:当设置了CornerRadius时,即使ClipToBounds="False",Border 也会自动裁剪子元素到圆角区域

五、核心依赖属性逐行解析

1.Background属性

C#:

[Bindable(true)][Category("Appearance")]publicBrushBackground{get;set;}
  • 作用:设置 Border 的背景色。

  • 支持的画刷类型

    • 纯色画刷:SolidColorBrush
    • 渐变画刷:LinearGradientBrushRadialGradientBrush
    • 图像画刷:ImageBrush
    • 视觉画刷:VisualBrush
工业场景应用:

xaml:

<!-- 纯色背景 --> <Border Background="#F5F5F5"/> <!-- 渐变背景 --> <Border> <Border.Background> <LinearGradientBrush StartPoint="0,0" EndPoint="1,1"> <GradientStop Color="#FFFFFF" Offset="0"/> <GradientStop Color="#F5F5F5" Offset="1"/> </LinearGradientBrush> </Border.Background> </Border>

2.BorderBrushBorderThickness属性

csharp:

[Bindable(true)] [Category("Appearance")] public Brush BorderBrush { get; set; } [Bindable(true)] [Category("Appearance")] public Thickness BorderThickness { get; set; }
  • BorderBrush:设置边框的颜色
  • BorderThickness:设置边框的厚度,支持分别设置四个边的厚度
  • 注意:只有当BorderThickness大于 0 且BorderBrush不是透明时,边框才会显示
示例:

xaml:

<!-- 四个边相同厚度 --> <Border BorderBrush="#E0E0E0" BorderThickness="1"/> <!-- 不同边不同厚度 --> <Border BorderBrush="#E0E0E0" BorderThickness="1,0,1,0"/> <!-- 只有左右边框 -->

3.CornerRadius属性(灵魂属性)

C#:

[Bindable(true)] [Category("Appearance")] public CornerRadius CornerRadius { get; set; }
  • 作用:设置 Border 的圆角半径。

  • 语法

    • 统一圆角:CornerRadius="4"(四个角都是 4 像素)
    • 分别设置:CornerRadius="4,4,0,0"(左上角和右上角 4 像素,右下角和左下角 0 像素)
  • 工业场景最佳实践:工业界面推荐使用 2-4 像素的圆角,既美观又不显得过于花哨。

示例:

XAML:

<!-- 统一圆角 --> <Border CornerRadius="4" Background="White" BorderBrush="#E0E0E0" BorderThickness="1"/> <!-- 顶部圆角 --> <Border CornerRadius="4,4,0,0" Background="#2196F3" Foreground="White"/>

4.Padding属性

C#:

[Bindable(true)] [Category("Layout")] public Thickness Padding { get; set; }
  • 作用:设置子元素与 Border 边框之间的内边距。

  • Margin的区别

    • Padding:内部间距,子元素与 Border 之间的距离。
    • Margin:外部间距,Border 与其他控件之间的距离。
示例:

XAML:

<Border Padding="10" Background="White" BorderBrush="#E0E0E0" BorderThickness="1"> <TextBlock Text="这是一个带内边距的文本"/> </Border>

5.ClipToBounds属性

C#:

[Bindable(true)][Category("Appearance")]publicboolClipToBounds{get;set;}
  • 作用:控制是否裁剪超出 Border 边界的子元素内容。
  • 默认值false
  • 重要特性:当设置了CornerRadius时,即使ClipToBounds="False",Border 也会自动裁剪子元素到圆角区域。
  • 工业场景应用:当子元素可能超出 Border 边界时,设置ClipToBounds="True"可以防止内容溢出。

六、受保护方法逐行解析

1.MeasureOverride()方法

C#:

protectedoverrideSizeMeasureOverride(Sizeconstraint);
  • 触发时机:当 Border 需要测量自身大小时调用。

  • 核心逻辑

    1. 计算边框和内边距的总大小
    2. 测量子元素的大小,可用空间为总大小减去边框和内边距
    3. 子元素的测量大小加上边框和内边距,得到 Border 的总大小
  • 设计意图:确保 Border 的大小能够容纳子元素、边框和内边距。

2.ArrangeOverride()方法

csharp:

protected override Size ArrangeOverride(Size finalSize);
  • 触发时机:当 Border 需要排列子元素时调用

  • 核心逻辑

    1. 计算子元素的可用区域:总大小减去边框和内边距
    2. 将子元素排列在可用区域的左上角
  • 设计意图:确保子元素被正确排列在边框和内边距内部

3.OnRender()方法

C#:

protected override void OnRender(DrawingContext drawingContext);
  • 触发时机:当 Border 需要渲染自身时调用

  • 核心逻辑

    1. 绘制背景(如果 Background 不是透明)
    2. 绘制边框(如果 BorderThickness 大于 0 且 BorderBrush 不是透明)
  • 设计意图:实现 Border 的核心渲染逻辑

4.GetLayoutClip()方法

csharp:

protected override Geometry GetLayoutClip(Size layoutSlotSize);
  • 触发时机:当 WPF 需要获取控件的裁剪区域时调用

  • 核心逻辑

    • 如果设置了CornerRadius,返回一个圆角矩形作为裁剪区域
    • 否则返回基类的裁剪区域
  • 重要特性:这就是为什么设置了CornerRadius后,子元素会自动被裁剪到圆角区域的原因


七、Border 核心工作原理

7.1 测量流程

  1. 父容器调用 Border 的Measure方法,传入可用大小
  2. Border 调用MeasureOverride方法
  3. 计算边框和内边距的总大小:borderThickness + padding
  4. 计算子元素的可用大小:constraint - borderThickness - padding
  5. 调用子元素的Measure方法,传入子元素可用大小
  6. 计算 Border 的总大小:child.DesiredSize + borderThickness + padding
  7. 返回总大小作为 Border 的测量结果

7.2 排列流程

  1. 父容器调用 Border 的Arrange方法,传入最终大小
  2. Border 调用ArrangeOverride方法
  3. 计算子元素的可用区域:finalSize - borderThickness - padding
  4. 调用子元素的Arrange方法,将子元素排列在可用区域
  5. 返回最终大小作为 Border 的排列结果

7.3 渲染流程

  1. WPF 调用 Border 的OnRender方法,传入DrawingContext
  2. 如果Background不是透明,绘制背景矩形
  3. 如果BorderThickness大于 0 且BorderBrush不是透明,绘制边框
  4. 子元素在 Border 之上渲染
  5. 如果设置了CornerRadius,自动裁剪子元素到圆角区域

八、工业上位机典型应用实例

实例 1:工业按钮样式

这是工业界面中最常用的按钮样式,使用 Border 实现圆角、边框和背景效果。

xaml:

<Style x:Key="IndustrialButtonStyle" TargetType="Button"> <Setter Property="MinWidth" Value="100"/> <Setter Property="MinHeight" Value="40"/> <Setter Property="FontSize" Value="14"/> <Setter Property="Foreground" Value="#212121"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Button"> <Border x:Name="Border" Background="#F5F5F5" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4" Padding="12,6"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/> </Border> <ControlTemplate.Triggers> <Trigger Property="IsPressed" Value="True"> <Setter TargetName="Border" Property="Background" Value="#E0E0E0"/> </Trigger> <Trigger Property="IsEnabled" Value="False"> <Setter TargetName="Border" Property="Background" Value="#BDBDBD"/> <Setter Property="Foreground" Value="#757575"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style>

实例 2:设备状态卡片

xaml:

<Border Background="White" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4" Padding="15" Margin="10"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="设备A" FontSize="16" FontWeight="Bold" Margin="0 0 0 10"/> <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="0 0 0 5"> <TextBlock Text="状态:"/> <TextBlock Text="运行中" Foreground="#4CAF50" FontWeight="Bold"/> </StackPanel> <StackPanel Grid.Row="2" Orientation="Horizontal"> <TextBlock Text="产量:"/> <TextBlock Text="1234 件"/> </StackPanel> </Grid> </Border>

实例 3:参数输入框

xaml:

<Border Background="White" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4" Padding="5,3"> <TextBox BorderThickness="0" Background="Transparent" Text="{Binding ParameterValue}"/> </Border>

实例 4:分组框

xaml:

<Border Background="White" BorderBrush="#E0E0E0" BorderThickness="1" CornerRadius="4" Padding="10" Margin="10"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <TextBlock Grid.Row="0" Text="相机参数" FontSize="14" FontWeight="Bold" Margin="0 0 0 10"/> <Grid Grid.Row="1"> <!-- 参数输入控件 --> </Grid> </Grid> </Border>

九、最佳实践与常见问题(工业场景必看)

9.1 最佳实践

  1. 统一圆角大小:工业界面推荐使用 2-4 像素的圆角,保持界面风格一致
  2. 使用合适的边框颜色:推荐使用浅灰色(#E0E0E0)作为默认边框颜色
  3. 避免过厚的边框:边框厚度通常为 1 像素,最多不超过 2 像素
  4. 合理设置内边距:按钮的内边距推荐为 12,6,卡片的内边距推荐为 10-15
  5. 优先使用纯色背景:工业界面应避免过于复杂的背景,保持简洁清晰
  6. 利用 Border 实现视觉层次:通过不同的背景色和边框区分不同的功能区域

9.2 常见问题与解决方案

问题 1:子元素超出圆角区域

原因:WPF 的默认裁剪行为不会裁剪到圆角

解决方案:使用 Border 包裹子元素,Border 会自动裁剪子元素到圆角区域

问题 2:边框模糊

原因:边框位置与像素网格不对齐

解决方案:设置UseLayoutRounding="True",确保边框对齐像素网格

xaml:

<Border UseLayoutRounding="True" BorderBrush="#E0E0E0" BorderThickness="1"/>
问题 3:圆角不光滑

原因:默认的抗锯齿效果不够好

解决方案:设置RenderOptions.BitmapScalingMode="HighQuality"

xaml:

<Border RenderOptions.BitmapScalingMode="HighQuality" CornerRadius="4"/>
问题 4:背景色覆盖了边框

原因:背景色绘制在边框之上

解决方案:确保 BorderThickness 大于 0,并且 BorderBrush 不是透明

问题 5:性能问题

原因:使用了复杂的画刷(如渐变画刷、图像画刷)或过大的圆角

解决方案

  • 优先使用纯色画刷
  • 避免使用过大的圆角(超过 20 像素)
  • 不要在频繁更新的区域使用复杂的 Border 效果

十、官方设计意图总结

微软设计 Border 的核心目标是:

  1. 提供轻量级的装饰器控件:专门用于为其他控件添加视觉装饰
  2. 实现完整的视觉装饰能力:支持背景、边框、圆角和内边距
  3. 自动处理圆角裁剪:解决子元素超出圆角的问题
  4. 保持高性能:没有复杂的逻辑,渲染效率极高
  5. 易于使用:通过简单的属性设置即可实现丰富的视觉效果

总结

Border是 WPF 中最基础、最常用的装饰器控件,它的核心特性包括:

  • Background:设置背景色
  • BorderBrushBorderThickness:设置边框
  • CornerRadius:实现圆角效果
  • Padding:设置内边距
  • 自动裁剪子元素到圆角区域

在工业上位机开发中,Border 是实现统一视觉风格的核心控件,几乎所有的按钮、卡片、输入框、分组框都需要使用 Border 来实现外观效果。掌握 Border 的正确使用方法,是开发美观、专业的工业界面的基础。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/5 20:13:50

结婚催婚:监狱最爱欢迎新人

“监狱最喜欢欢迎新人”:为什么结婚的人总爱催单身的人结婚? 目录 “监狱最喜欢欢迎新人”:为什么结婚的人总爱催单身的人结婚? 为什么结婚的人,总爱催别人结婚? 为什么单身的人,从不劝人离婚? 真正的成熟,是不把自己的选择当标准答案 刷到一张图,一句话配一条神评论…

作者头像 李华
网站建设 2026/8/5 20:10:37

145、LLC谐振变换器的冗余设计

145、LLC谐振变换器的冗余设计 一次让我通宵的现场故障 去年冬天,某通信电源项目在客户机房批量炸机。现场反馈:某批次48V/3kW模块在电网波动时,约15%的模块出现IGBT短路、谐振电容鼓包。我连夜飞过去,拆开故障模块,发现一个诡异现象——所有炸机的模块,LLC谐振频率都偏…

作者头像 李华
网站建设 2026/8/5 20:07:24

基于分形哲学的非线性叙事游戏架构设计与Unity实现

在游戏开发与叙事设计的交叉领域&#xff0c;我们常常会遇到一个迷人的挑战&#xff1a;如何讲述一个无法被传统线性结构所容纳的故事&#xff1f;无论是《星际拓荒》中等待宇宙终结的循环&#xff0c;还是《史丹利的寓言》里对叙事本身的解构&#xff0c;非线性叙事正成为游戏…

作者头像 李华
网站建设 2026/8/5 20:07:20

JavaScript对象数组遍历与查找:for...in、Object.entries、find与filter实战

1. 项目概述&#xff1a;从“遍历”与“查找”说起在数据处理和前端开发中&#xff0c;我们几乎每天都要和对象数组打交道。比如&#xff0c;你从后端拿到一个用户列表&#xff0c;每个用户是一个对象&#xff0c;包含id、name、email等属性&#xff0c;整个列表就是一个对象数…

作者头像 李华