65.9K
CodeProject 正在变化。 阅读更多。
Home

C# 中的复杂属性

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.55/5 (13投票s)

2008年9月5日

CPOL

4分钟阅读

viewsIcon

45455

downloadIcon

891

C#中的“复杂属性”和Size3D。

size3dclassdiag.png

引言

这篇文章的灵感来自于尝试改进一个在Code Project上发布的用户控件的代码。该控件有一个接受一系列整数的属性。作者处理此属性的方式,委婉地说,是一个混乱的技巧——所以我着手尝试改进它,因为我喜欢该控件本身的想法。

不幸的是,事实证明,微软并没有使这个过程变得非常容易,而且我发现相关的文档/在线资源非常稀少。查看一些.NET源代码并研究其他几篇文章的源代码后,我最终成功地使其完全工作,所以我认为我应该分享我的发现。

什么是复杂属性?

复杂属性是指具有多个值的属性。一个很好的例子是System.Drawing.Size结构,它用作大多数控件中的属性,它基本上是用一个属性表示的两个整数。

Size3D

Size3D是我在这里创建的用于演示如何实现复杂属性的结构。它与.NET Size结构非常相似,但它显然需要宽度、高度和深度值。此示例仅用于演示如何创建复杂属性,并非旨在成为一个完整的“可用于生产”的3D结构!

基础知识(初学者内容)

首先是创建三个成员变量……

private int m_Width;
private int m_Height;
private int m_Depth;

……和三个对应的属性。

public int Width
{
    get { return m_Width; }
    set { m_Width = ValidateValue(value); }
}
public int Height
{
    get { return m_Height; }
    set { m_Height = ValidateValue(value); }
}
public int Depth
{
    get { return m_Depth; }
    set { m_Depth = ValidateValue(value); }
}

如您所见,每个setter都调用一个ValidateValue方法,该方法将值限制在最小值和最大值(我已将其声明为常量)。

public const int FieldMinValue = 1;
public const int FieldMaxValue = 255;

我将FieldMaxValue限制为一个较低的值,因为我希望总容量在Int32的范围内(在此示例中,这仅适用于GetHashCode方法)。

下一步是创建一个简单的构造函数,它接受三个int并将其分配给成员变量……

public Size3D(int width, int height, int depth)
{
m_Width = ValidateValue(width);
m_Height = ValidateValue(height);
m_Depth = ValidateValue(depth);
}

……和一个静态的“Empty”Size3D

public static readonly Size3D Empty = new Size3D();

后续步骤(稍微高级一些)

接下来,我们需要通过添加一些运算符重载(请参阅我的文章:C#运算符重载简介[^] 以获取更多解释)并重写EqualsGetHashCodeToString方法来允许对我们的结构进行一些基本的数学计算和比较运算。为方便起见,我还添加了静态AddSubtract方法以及非静态只读IsEmpty属性。

这就是创建的结构。为了能够将其用作属性,我们需要通过应用引用我们转换器类的TypeConverter属性来向其添加一个TypeConverter。

[TypeConverter(typeof(Size3DConverter))]

Size3DConverter(更高级)

这是在一些重写的方法和我们自己的GetSize3DType方法中完成实际工作的地方。此类派生自System.ComponentModel.TypeConverter。我们基本上做的就是转换属性网格中我们结构的字符串表示形式。

我尝试了很多组合,似乎为了使我们的结构与内置类型完全一样工作,我们需要重写以下方法。

  • CanConvertFrom
  • CanConvertTo
  • ConvertFrom
  • ConvertTo
  • CreateInstance
  • GetCreateInstanceSupported
  • GetProperties
  • GetPropertiesSupported

许多方法都调用其他方法,因此很难单独解释它们,所以我不会在这里尝试。如果您逐步遵循源代码,则此工作示例应该是可以自解释的。有趣的是,我们需要使用反射和结构的属性来动态创建新实例(在需要时)。

Control3D

这是一个非常基本的控件(同样,并非可用于生产!),我创建它来测试和演示Size3D结构。

它有一个属性 - Size3D - 一个成员变量,属性获取和设置它,以及重写的OnPaint方法,用于根据Size3D值绘制立方体/长方体。

使用中

演示应用程序使用属性网格显示Control3D实例的属性。默认属性是Size3D,它将自动被选中,并且默认为100、100、100。请注意,这些值(除非您更改它们)不会以粗体显示,也不会出现在窗体的designer.cs文件中,因为它们仅在需要时才由设计器序列化。更改任何一个或所有值,控件将重新绘制。

历史

  • 初始版本 - 2008年9月5日。
© . All rights reserved.