using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection.Emit;
using System.Reflection;
using System.Xml;
namespace ebsoft.Xml.Factory
{
public abstract class XmlClassBase
{
protected System.Xml.XmlNode _data;
}
public enum NodeValueType
{
AttributeValue,
NodeInnerXml,
Node
}
public class NodeValueAttribute : Attribute
{
private NodeValueType _Type = NodeValueType.AttributeValue;
public NodeValueType Type
{
get
{
return _Type;
}
set
{
_Type = value;
}
}
private string _NodeName;
public string NodeName
{
get
{
return _NodeName;
}
set
{
_NodeName = value;
}
}
public NodeValueAttribute()
{
}
public NodeValueAttribute(string nodeName, NodeValueType type)
{
_Type = type;
_NodeName = nodeName;
}
public NodeValueAttribute(NodeValueType type)
{
_Type = type;
}
}
public class XmlClassFactory<T>
{
private static Type _CreatedType;
public static T CreateInstance(XmlNode Data)
{
if (_CreatedType == null)
_CreatedType = CreateClass();
return (T)Activator.CreateInstance(_CreatedType, Data);
}
private static Type CreateClass()
{
Type t = typeof(T);
//if (t.IsGenericType)
// throw new Exception("T必须不能为泛型");
if (!t.IsSubclassOf(typeof(XmlClassBase)))
throw new Exception("T必须从XmlClassBase派生");
string name = "XmlHelper.Factory." + t.Name;
AssemblyName asmName = new AssemblyName(name);
AppDomain domain = AppDomain.CurrentDomain;
AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name);
//AssemblyBuilder assemblyBuilder = domain.DefineDynamicAssembly(asmName, AssemblyBuilderAccess.RunAndSave);
//ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(name, "s.dll");
TypeBuilder typeBuilder = moduleBuilder.DefineType(name, TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed, t, Type.EmptyTypes);
PropertyInfo[] pis = t.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
foreach (PropertyInfo pi in pis)
{
MethodInfo miget = pi.GetGetMethod(true);
if (!miget.IsAbstract)
continue;
MethodInfo miset = pi.GetSetMethod(true);
object[] FieldAttribute = pi.GetCustomAttributes(typeof(NodeValueAttribute), false);
string FieldName = "";
if (FieldAttribute.Length == 0)
{
throw new Exception(string.Format("抽象属性{0}必须标识NodeValueAttribute属性", pi.Name));
}
NodeValueAttribute fa = (NodeValueAttribute)FieldAttribute[0];
if (pi.PropertyType.FullName != "System.String" && fa.Type != NodeValueType.Node)
{
throw new Exception(string.Format("抽象属性{0}被标识为{1},因此他的类型必须定义为String", pi.Name , fa.Type));
}
if (fa.Type == NodeValueType.Node && pi.PropertyType.FullName != "System.Xml.XmlNode")
{
throw new Exception(string.Format("抽象属性{0}被标识为{1},因此他的类型必须定义为XmlNode", pi.Name , fa.Type));
}
if (fa.NodeName == null)
{
FieldName = pi.Name;
}
else
{
FieldName = fa.NodeName;
}
PropertyBuilder propertyBuilder = typeBuilder.DefineProperty(pi.Name, PropertyAttributes.HasDefault, pi.PropertyType, Type.EmptyTypes);
MethodAttributes getMethodAttribute = MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
if (miget.IsFamily)
getMethodAttribute = getMethodAttribute | MethodAttributes.Family;
else
getMethodAttribute = getMethodAttribute | MethodAttributes.Public;
MethodBuilder getPropertyBuilder = typeBuilder.DefineMethod("get_" + pi.Name, getMethodAttribute, pi.PropertyType, Type.EmptyTypes);
ILGenerator getIL = getPropertyBuilder.GetILGenerator();
switch (fa.Type)
{
case NodeValueType.AttributeValue:
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Attributes", BindingFlags.Instance | BindingFlags.Public));
getIL.Emit(OpCodes.Ldstr, FieldName);
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlAttributeCollection).GetMethod("get_ItemOf", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) } , null));
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Value", BindingFlags.Public | BindingFlags.Instance));
getIL.Emit(OpCodes.Ret);
break;
case NodeValueType.NodeInnerXml:
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
getIL.Emit(OpCodes.Ldstr, FieldName);
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) } , null));
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_InnerXml", BindingFlags.Public | BindingFlags.Instance));
getIL.Emit(OpCodes.Ret);
break;
case NodeValueType.Node:
getIL.Emit(OpCodes.Ldarg_0);
getIL.Emit(OpCodes.Ldfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
getIL.Emit(OpCodes.Ldstr, FieldName);
getIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) } , null));
getIL.Emit(OpCodes.Ret);
break;
default:
break;
}
propertyBuilder.SetGetMethod(getPropertyBuilder);
if (miset == null)
{
continue;
}
MethodAttributes setMethodAttribute = MethodAttributes.SpecialName | MethodAttributes.HideBySig | MethodAttributes.Virtual;
if (miset.IsFamily)
setMethodAttribute = setMethodAttribute | MethodAttributes.Family;
else
setMethodAttribute = setMethodAttribute | MethodAttributes.Public;
MethodBuilder setPropertyBuilder = typeBuilder.DefineMethod("set_" + pi.Name, setMethodAttribute, null, new Type[] { typeof(string) });
ILGenerator setIL = setPropertyBuilder.GetILGenerator();
switch (fa.Type)
{
case NodeValueType.AttributeValue:
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
setIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Attributes", BindingFlags.Instance | BindingFlags.Public));
setIL.Emit(OpCodes.Ldstr, FieldName);
setIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlAttributeCollection).GetMethod("get_ItemOf", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) } , null));
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("set_Value", BindingFlags.Public | BindingFlags.Instance));
setIL.Emit(OpCodes.Ret);
break;
case NodeValueType.NodeInnerXml:
setIL.Emit(OpCodes.Ldarg_0);
setIL.Emit(OpCodes.Ldfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
setIL.Emit(OpCodes.Ldstr, FieldName);
setIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("get_Item", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(string) } , null));
setIL.Emit(OpCodes.Ldarg_1);
setIL.Emit(OpCodes.Callvirt, typeof(System.Xml.XmlNode).GetMethod("set_InnerXml", BindingFlags.Public | BindingFlags.Instance));
setIL.Emit(OpCodes.Ret);
break;
case NodeValueType.Node:
break;
default:
break;
}
propertyBuilder.SetSetMethod(setPropertyBuilder);
}
ConstructorBuilder cb = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, new Type[] { typeof(System.Xml.XmlNode) });
ILGenerator cbil = cb.GetILGenerator();
cbil.Emit(OpCodes.Ldarg_0);
cbil.Emit(OpCodes.Ldarg_1);
cbil.Emit(OpCodes.Stfld, t.BaseType.GetField("_data", BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance));
cbil.Emit(OpCodes.Ldarg_0);
cbil.Emit(OpCodes.Call, t.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public, null, Type.EmptyTypes, null));
cbil.Emit(OpCodes.Ret);
Type t1 = typeBuilder.CreateType();
//assemblyBuilder.Save("s.dll");
return t1;
}
}
}
用法
public abstract class HOME : XmlClassBase
{
/// <summary>
/// <para>-1001 未登录</para>
/// <para>-31011 现在系统繁忙,稍后再试。</para>
/// </summary>
[NodeValue]
public abstract string code { get;}
[NodeValue]
public abstract string message { get;}
}
return XmlClassFactory<需要付值的类>.CreateInstance("XML节点");