您的位置:首页 > 其它

Silverlight中动态数据验证和动态自动计算的Reflection反射实现

2011-06-25 18:46 627 查看

Silverlight中动态数据验证和动态自动计算的Reflection反射实现

上周在博客园发了个首页随笔,因为被误认为是广告而被移出首页,这次发首页,特地备足了技术材料,结合FreeForm实际的开发情况,从技术上分析在Silverlight中实现动态数据验证和自动计算的方法。我们知道在.Net 4.0标准类库中,反射的类很全,非常好用,但在Silverlight类库中涉及反射的命名空间虽然也有System.Reflection 和System.Reflection.Emit ,但类和方法大大的缩减了。以前我们在WinForm或者ASP.Net中实现动态验证和动态计算非常容易,可以通过类似如下代码实现:

View Code

class Example

{

public static void Demo(System.Windows.Controls.TextBlock outputBlock)

{

AssemblyName aName = new AssemblyName("DynamicAssemblyExample");

AssemblyBuilder ab =

AppDomain.CurrentDomain.DefineDynamicAssembly(

aName,

AssemblyBuilderAccess.Run);

// Create the module.

ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);

TypeBuilder tb = mb.DefineType(

"MyDynamicType",

TypeAttributes.Public);

// Add a private field of type int (Int32).

FieldBuilder fbNumber = tb.DefineField(

"m_number",

typeof(int),

FieldAttributes.Private);

// Define a constructor that takes an integer argument and

// stores it in the private field.

Type[] parameterTypes = { typeof(int) };

ConstructorBuilder ctor1 = tb.DefineConstructor(

MethodAttributes.Public,

CallingConventions.Standard,

parameterTypes);

ILGenerator ctor1IL = ctor1.GetILGenerator();

// For a constructor, argument zero is a reference to the new

// instance. Push it on the stack before calling the base

// class constructor. Specify the default constructor of the

// base class (System.Object) by passing an empty array of

// types (Type.EmptyTypes) to GetConstructor.

ctor1IL.Emit(OpCodes.Ldarg_0);

ctor1IL.Emit(OpCodes.Call,

typeof(object).GetConstructor(Type.EmptyTypes));

// Push the instance on the stack before pushing the argument

// that is to be assigned to the private field m_number.

ctor1IL.Emit(OpCodes.Ldarg_0);

ctor1IL.Emit(OpCodes.Ldarg_1);

ctor1IL.Emit(OpCodes.Stfld, fbNumber);

ctor1IL.Emit(OpCodes.Ret);

// Define a default constructor that supplies a default value

// for the private field. For parameter types, pass the empty

// array of types or pass null.

ConstructorBuilder ctor0 = tb.DefineConstructor(

MethodAttributes.Public,

CallingConventions.Standard,

Type.EmptyTypes);

ILGenerator ctor0IL = ctor0.GetILGenerator();

// For a constructor, argument zero is a reference to the new

// instance. Push it on the stack before pushing the default

// value on the stack, then call constructor ctor1.

ctor0IL.Emit(OpCodes.Ldarg_0);

ctor0IL.Emit(OpCodes.Ldc_I4_S, 42);

ctor0IL.Emit(OpCodes.Call, ctor1);

ctor0IL.Emit(OpCodes.Ret);

// Define a property named Number that gets and sets the private

// field.

//

// The last argument of DefineProperty is null, because the

// property has no parameters. (If you don't specify null, you must

// specify an array of Type objects. For a parameterless property,

// use the built-in array with no elements: Type.EmptyTypes)

PropertyBuilder pbNumber = tb.DefineProperty(

"Number",

PropertyAttributes.HasDefault,

typeof(int),

null);

// The property "set" and property "get" methods require a special

// set of attributes.

MethodAttributes getSetAttr = MethodAttributes.Public |

MethodAttributes.SpecialName | MethodAttributes.HideBySig;

// Define the "get" accessor method for Number. The method returns

// an integer and has no arguments. (Note that null could be

// used instead of Types.EmptyTypes)

MethodBuilder mbNumberGetAccessor = tb.DefineMethod(

"get_Number",

getSetAttr,

typeof(int),

Type.EmptyTypes);

ILGenerator numberGetIL = mbNumberGetAccessor.GetILGenerator();

// For an instance property, argument zero is the instance. Load the

// instance, then load the private field and return, leaving the

// field value on the stack.

numberGetIL.Emit(OpCodes.Ldarg_0);

numberGetIL.Emit(OpCodes.Ldfld, fbNumber);

numberGetIL.Emit(OpCodes.Ret);

// Define the "set" accessor method for Number, which has no return

// type and takes one argument of type int (Int32).

MethodBuilder mbNumberSetAccessor = tb.DefineMethod(

"set_Number",

getSetAttr,

null,

new Type[] { typeof(int) });

ILGenerator numberSetIL = mbNumberSetAccessor.GetILGenerator();

// Load the instance and then the numeric argument, then store the

// argument in the field.

numberSetIL.Emit(OpCodes.Ldarg_0);

numberSetIL.Emit(OpCodes.Ldarg_1);

numberSetIL.Emit(OpCodes.Stfld, fbNumber);

numberSetIL.Emit(OpCodes.Ret);

// Last, map the "get" and "set" accessor methods to the

// PropertyBuilder. The property is now complete.

pbNumber.SetGetMethod(mbNumberGetAccessor);

pbNumber.SetSetMethod(mbNumberSetAccessor);

// Define a method that accepts an integer argument and returns

// the product of that integer and the private field m_number. This

// time, the array of parameter types is created on the fly.

MethodBuilder meth = tb.DefineMethod(

"MyMethod",

MethodAttributes.Public,

typeof(int),

new Type[] { typeof(int) });

ILGenerator methIL = meth.GetILGenerator();

// To retrieve the private instance field, load the instance it

// belongs to (argument zero). After loading the field, load the

// argument one and then multiply. Return from the method with

// the return value (the product of the two numbers) on the

// execution stack.

methIL.Emit(OpCodes.Ldarg_0);

methIL.Emit(OpCodes.Ldfld, fbNumber);

methIL.Emit(OpCodes.Ldarg_1);

methIL.Emit(OpCodes.Mul);

methIL.Emit(OpCodes.Ret);

// Finish the type.

Type t = tb.CreateType();

// The code can be executed immediately. Start by getting reflection

// objects for the method and the property.

MethodInfo mi = t.GetMethod("MyMethod");

PropertyInfo pi = t.GetProperty("Number");

// Create an instance of MyDynamicType using the default

// constructor.

object o1 = Activator.CreateInstance(t);

// Display the value of the property, then change it to 127 and

// display it again. Use null to indicate that the property

// has no index.

outputBlock.Text += String.Format("o1.Number: {0}\n", pi.GetValue(o1, null));

pi.SetValue(o1, 127, null);

outputBlock.Text += String.Format("o1.Number: {0}\n", pi.GetValue(o1, null));

// Call MyMethod, passing 22, and display the return value, 22

// times 127. Arguments must be passed as an array, even when

// there is only one.

object[] arguments = { 22 };

outputBlock.Text += String.Format("o1.MyMethod(22): {0}\n",

mi.Invoke(o1, arguments));

// Create an instance of MyDynamicType using the constructor

// that specifies m_Number. The constructor is identified by

// matching the types in the argument array. In this case,

// the argument array is created on the fly. Display the

// property value.

object o2 = Activator.CreateInstance(t,

new object[] { 5280 });

outputBlock.Text += String.Format("o2.Number: {0}\n", pi.GetValue(o2, null));

}

}


好了,原理清晰了,一起看看在Siverlight上实现的例子吧(一定要看最后一节的“动态自定义验证

”),感谢大家。

在线演示(ver2011):

http://crmwin.com/FreeForm2011TestPage.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐