此属性(Attribute )而非彼属性(Property)。MSDN描述:属性(Attribute )能够提供功能强大的方法,以将声明信息与 C# 代码(类型、方法、属性等)相关联。一旦属性与程序实体关联,即可在运行时使用名为反射的技术对属性进行查询。属性 (Attribute) 描述如何将数据序列化,指定用于强制安全性的特性,并限制实时 (JIT) 编译器的优化,从而使代码易于调试。属性 (Attribute) 还可以记录文件名或代码作者,或在窗体开发阶段控制控件和成员的可见性等等。


属性具有以下特点:
- 属性可向程序中添加元数据。元数据是嵌入程序中的信息,如编译器指令或数据描述。
- 程序可以使用反射检查自己的元数据。请参见使用反射访问属性。
- 通常使用属性与 COM 交互。
经过对属性的研究我们做一个小示例,用于阐明属性的使用。我们尝试写个方法,它以两个对象为参数,然后将源对象运行时的所有字段值都拷贝给目标对象。按照一般情况,只要是可序列化的类、字段和方法都可以通过反射机制完成上述操作。但是如果遇到[NonSerialized]限定的字段我们将无从下手。面对这种情形我们创建一个方法,不仅可以存取[Serialized]限定的字段,还可以还原那些经[NonSerialized]限定的字段并在运行时重新赋值!
我们先创建一个可序列化的类:
[Serializable]
public class FooClass
{
public int data1;
[NonSerialized] public int data2;
public FooClass(int data1, int data2)
{
this.data1 = data1;
this.data2 = data2;
}
}
然后在Button1的Click事件中添加如下代码:
private void button1_Click(object sender, EventArgs e)
{
FooClass destObject = new FooClass(10, 20);
FooClass sourceObject = new FooClass(10, 30);
MessageBox.Show("destObject.data2: "+destObject.data2+'\n'+"sourceObject.data2: "+sourceObject.data2);
RestoreUtils.RestoreNonSerialized(destObject, sourceObject);
MessageBox.Show("destObject.data2: " + destObject.data2 + '\n' + "sourceObject.data2: " + sourceObject.data2);
}
注意,RestoreUtils.RestoreNonSerialized()方法,
public class RestoreUtils
{
const BindingFlags flags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
public static void RestoreNonSerialized(object dest, object source)
{
if (dest == null || source == null)
return;
Type objectType = dest.GetType();
if (objectType.IsPrimitive | objectType.IsValueType)
return;
FieldInfo[] dstFieldsInfo = objectType.GetFields(flags);
FieldInfo[] srcFieldsInfo = source.GetType().GetFields(flags);
for (int fieldIndex = 0; fieldIndex < dstFieldsInfo.Length; fieldIndex++)
{
FieldInfo fieldInfo = dstFieldsInfo[fieldIndex];
if (fieldInfo.IsNotSerialized)
{
object newValue = srcFieldsInfo[fieldIndex].GetValue(source);
fieldInfo.SetValue(dest, newValue);
continue;
}
object dstFieldObject = fieldInfo.GetValue(dest);
object srcFieldObject = srcFieldsInfo[fieldIndex].GetValue(source);
if (dstFieldObject != null && srcFieldObject != null)
RestoreNonSerialized(dstFieldObject, srcFieldObject);
}
IEnumerable dstEnumerable = dest as IEnumerable;
if (dstEnumerable != null)
{
IEnumerable srcEnumerable = source as IEnumerable;
if (srcEnumerable != null)
{
IEnumerator srcEnumerator = srcEnumerable.GetEnumerator();
foreach (Object dstItem in dstEnumerable)
{
bool next = srcEnumerator.MoveNext();
if (!next)
break;
Object srcItem = srcEnumerator.Current;
RestoreNonSerialized(dstItem, srcItem);
}
}
}
}
}
我们会发现,FooClass类的data2字段为不可序列化字段,在没有还原不可序列化的字段之前,destObject.data2和sourceObject.data2的值是不同的,为20和30,当我们还原并将sourceObject.data2在运行时的值拷贝给destObject.data2后,两个FooClass类的实例的data2字段就完全一样了。