代码改变世界

[原创]通过Attribute完成中文智能提示

2009-07-29 14:10  水随风  阅读(349)  评论(1编辑  收藏  举报

前言

  Attribute作为”特性”,可运用的范围是很广的,而且运用的场景也是非常的灵活。Attribute在MSDN中是这样解释的(有删减):

Attribute 的系信息或用的自定信息与目元素相关联。目元素可以是程序集、、构造函数、委托、枚、事件、字段、接口、方法、可移植可行文件模、参数、属性 (Property)、返回构或其他属性 (Attribute) 

所有属性型都直接或接地从 Attribute 派生。属性可用于任何目元素;多个属性可用于同一目元素;并且属性可由从目元素派生的元素承。 

 

  如果在实际场景中使用Attribute呢?可以看到,在很多的组件编写时,会在属性前面加上一些特定的Attribute,之后就可以在设计界面的属性设计器中看到。

场景

 

  在一些大型的桌面系统开发中,会重构出很多的基础控件。这些强大的基础控件,进而构造出非常复杂的画面,实际上这些画面也有很多的共性,所以又会抽出基础Form进行继承开发,减少开发业务的复杂度,提高了开发人员的开发效率。

而在一般的大型项目中,会有专门的一块业务,作为”系统管理员”操作的部分。实际上这些”系统管理员”对编程和系统一窍不通,但是他们明白式样,明白简单的逻辑。所以为了提供给他们很好的去操作画面上的控件。提供了一个功能,就是在管理画面将这些控件用中文的形式显示出来,并且属性的访问也用中文的形式,这样他们就可以写出简单的逻辑去管理和维护业务画面。在这里我们就用到了Attribute的强大功能,去完成这个操作。比如:当前台画面上有检索部分和结果显示部分,这部分需要动态进行SQL拼接=>

姓名.文字 != ‘’
{
      AND sql1
}
 
姓名.文字 == ‘’
{
      AND sql2
}
 

实例

  首先,我们需要创建一个SomeClassCNAttribute和一个SomePropertyCNAttribute类,用以对开发的控件进行说明,他们都继承于Attribute:

 

   1:  public class SomeClassCNAttribute : Attribute
   2:      {
   3:          private string _name;
   4:   
   5:          public string Name
   6:          {
   7:              get { return _name; }
   8:              set { _name = value; }
   9:          }
  10:          public SomeClassCNAttribute(string strName)
  11:          {
  12:              _name = strName;
  13:          }
  14:      }
  15:   
  16:  public  class SomePropertyCNAttribute : Attribute
  17:      {
  18:          private string _name;
  19:   
  20:          public string Name
  21:          {
  22:              get { return _name; }
  23:              set { _name = value; }
  24:          }
  25:         public SomePropertyCNAttribute(string strName)
  26:         {
  27:             _name = strName;
  28:         }
  29:      }
  30:   
  这两个属性是准备用来对说明类库用途的。如:
  32:  [SomeClassCN("基本信息1")]
  33:      public class SomePropertyCopy
  34:      {
  35:          private string strRealName;
  36:          [SomePropertyCN("姓名")]
  37:          public string StrRealName
  38:          {
  39:              get { return strRealName; }
  40:              set { strRealName = value; }
  41:          }
  42:          private string strSex;
  43:          [SomePropertyCN("性别")]
  44:          public string StrSex
  45:          {
  46:              get { return strSex; }
  47:              set { strSex = value; }
  48:          }
  49:          private string strEmail;
  50:          [SomePropertyCN("邮件")]
  51:          public string StrEmail
  52:          {
  53:              get { return strEmail; }
  54:              set { strEmail = value; }
  55:          }
  56:         
  57:          public SomePropertyCopy() { }
  58:   
  59:          public SomePropertyCopy(string name, string sex, string email)
  60:          {
  61:              strRealName = name;
  62:              strSex = sex;
  63:              strEmail = email;
  64:          }
  65:      }

  该类可以通过定义一个FCNExpression类库来读取中英文名并存入字典

image

 

  根据类来创建一个关于属性与方法的对应中英文的字典,每个类都看作一个树,树下有属性和方法名。

   1:  /// <summary>
   2:      /// 单位类,读取后存入表达库
   3:      /// </summary>
   4:      public class FCNExpression
   5:      {
   6:          #region 字段定义
   7:          private Type _type;
   8:          #endregion
   9:   
  10:          #region 构造函数
  11:          protected FCNExpression() { }
  12:   
  13:          public FCNExpression(object objTarget)
  14:              : this(objTarget.GetType())
  15:          {
  16:   
  17:          }
  18:   
  19:          public FCNExpression(Type type)
  20:              : this()
  21:          {
  22:              _type = type;
  23:          }
  24:          #endregion
  25:   
  26:          #region 属性定义
  27:          private List<ExpressionItem> _innerExpressions = null;
  28:          /// <summary>
  29:          /// 内部字典
  30:          /// </summary>
  31:          public List<ExpressionItem> InnerExpressions
  32:          {
  33:              get
  34:              {
  35:                  if (_innerExpressions == null)
  36:                  {
  37:                      _innerExpressions = GetSomePropertyAttributesDirecs(_type);
  38:                  }
  39:                  return _innerExpressions;
  40:              }
  41:          }
  42:          /// <summary>
  43:          /// 中文类名
  44:          /// </summary>
  45:          public string ClassCNName
  46:          {
  47:              get
  48:              {
  49:                  if (_type.IsDefined(typeof(SomeClassCNAttribute), false))
  50:                  {
  51:                      SomeClassCNAttribute sccna =
  52:                          Attribute.GetCustomAttribute(_type, typeof(SomeClassCNAttribute)) as SomeClassCNAttribute;
  53:                      return sccna.Name;
  54:                  }
  55:                  return string.Empty;
  56:              }
  57:          }
  58:          #endregion
  59:   
  60:          #region 方法定义
  61:          /// <summary>
  62:          /// 取得定义为SomeProperty的属性
  63:          /// </summary>
  64:          /// <param name="objTarget"></param>
  65:          private List<ExpressionItem> GetSomePropertyAttributesDirecs(Type objType)
  66:          {
  67:              if (objType == null)
  68:              {
  69:                  return null;
  70:              }
  71:              List<ExpressionItem> _dicExpressions = new List<ExpressionItem>();
  72:              //当前类型内定义的属性。
  73:              foreach (PropertyInfo pinfo in objType.GetProperties())
  74:              {
  75:                  //循环查找是否定义过SomePropertyCNAttribute属性。
  76:                  if (pinfo.IsDefined(typeof(SomePropertyCNAttribute), false))
  77:                  {
  78:                      //将当前属性所定义的Attribute取得,读取定义名称,存入键值对。
  79:                      SomePropertyCNAttribute spcna =
  80:                          Attribute.GetCustomAttribute(pinfo, typeof(SomePropertyCNAttribute)) as SomePropertyCNAttribute;
  81:                      ExpressionItem eiNew = new ExpressionItem();
  82:                      eiNew.sCnName = spcna.Name;
  83:                      eiNew.sEnName = pinfo.Name;
  84:                      eiNew.ItemType = MemberTypes.Property;
  85:                      if (_dicExpressions.Contains(eiNew))
  86:                      {
  87:                          continue;
  88:                      }
  89:                      //存入中文与属性名 eg.<姓名,strName>
  90:                      _dicExpressions.Add(eiNew);
  91:                  }
  92:              }
  93:              foreach (MethodInfo minfo in objType.GetMethods(BindingFlags.Public))
  94:              {
  95:                  //循环查找是否定义过SomePropertyCNAttribute属性。
  96:                  if (minfo.IsDefined(typeof(SomeClassCNAttribute), false))
  97:                  {
  98:                      //将当前属性所定义的Attribute取得,读取定义名称,存入键值对。
  99:                      SomeClassCNAttribute spcna =
 100:                          Attribute.GetCustomAttribute(minfo, typeof(SomeClassCNAttribute)) as SomeClassCNAttribute;
 101:                      ExpressionItem eiNew = new ExpressionItem();
 102:                      eiNew.sCnName = spcna.Name;
 103:                      eiNew.sEnName = minfo.Name;
 104:                      eiNew.ItemType = MemberTypes.Method;
 105:                      if (_dicExpressions.Contains(eiNew))
 106:                      {
 107:                          continue;
 108:                      }
 109:                      //存入中文与属性名 eg.<姓名,strName>
 110:                      _dicExpressions.Add(eiNew);
 111:                  }
 112:              }
 113:              return _dicExpressions;
 114:          }
 115:          /// <summary>
 116:          /// 获取属性的值
 117:          /// </summary>
 118:          /// <param name="strCNName">中文名称</param>
 119:          /// <param name="objTarget">目标对象,获取该对象下的属性值</param>
 120:          /// <param name="index">索引,如果是集合的情况下用索引查找</param>
 121:          /// <returns>Value值</returns>
 122:          public object GetPropertyValueByCNName(string strCNName, object objTarget, params object[] index)
 123:          {
 124:              Type objType = objTarget.GetType();
 125:   
 126:              if (objType == null)
 127:              {
 128:                  return null;
 129:              }
 130:   
 131:              PropertyInfo pi = objType.GetProperty(InnerExpressions.Find((x) => x.sCnName == strCNName).sEnName);
 132:   
 133:              if (pi == null)
 134:              {
 135:                  return null;
 136:              }
 137:              return pi.GetValue(objTarget, index);
 138:          }
 139:          /// <summary>
 140:          /// 获取属性的值
 141:          /// </summary>
 142:          /// <param name="strCNName">中文名称</param>
 143:          /// <param name="objTarget">目标对象,获取该对象下的属性值</param>
 144:          /// <returns>Value值</returns>
 145:          public object GetPropertyValueByCNName(string strCNName, object objTarget)
 146:          {
 147:              return this.GetPropertyValueByCNName(strCNName, objTarget, null);
 148:          }
 149:          /// <summary>
 150:          /// 类中方法定义的获取
 151:          /// </summary>
 152:          /// <param name="strCNName">中文名</param>
 153:          /// <param name="objTarget">对象</param>
 154:          /// <param name="param">参数类型</param>
 155:          /// <returns></returns>
 156:          public object GetMethodValueByCnName(string strCNName, object objTarget, params object[] param)
 157:          {
 158:              Type objType = objTarget.GetType();
 159:   
 160:              if (objType == null)
 161:              {
 162:                  return null;
 163:              }
 164:              MemberInfo mi = objType.GetMethod(InnerExpressions.Find((x) => x.sCnName == strCNName).sEnName);
 165:   
 166:              if (mi == null)
 167:              {
 168:                  return null;
 169:              }
 170:              return mi;
 171:          }
 172:          #endregion
 173:   
 174:          #region 内部定义
 175:          public class ExpressionItem
 176:          {
 177:              private string _sCnName;
 178:   
 179:              public string sCnName
 180:              {
 181:                  get { return _sCnName; }
 182:                  set { _sCnName = value; }
 183:              }
 184:              private string _sEnName;
 185:   
 186:              public string sEnName
 187:              {
 188:                  get { return _sEnName; }
 189:                  set { _sEnName = value; }
 190:              }
 191:              public MemberTypes ItemType;
 192:          }
 193:          #endregion
 194:      }

   当每次输入到文本的时候,如果是圆点符号”.”则访问方法,将该输入的文本在创建的字典中查找如果有这个类库,则取出它包含的属性,加入到ListBox中,由ListBox在文本输入区域显示出来。

   1:  private bool GetItelliInfos(RichTextBox rtb)
   2:          {
   3:              int startno = 1;
   4:              string strName = string.Empty;
   5:              while (true)
   6:              {
   7:                  if (rtxtExpression.SelectionStart - startno < 0)
   8:                  {
   9:                      strName = rtxtExpression.Text.Substring(0, startno - 1).Trim();
  10:   
  11:                      break;
  12:                  }
  13:                  if (rtxtExpression.Text.Substring(rtxtExpression.SelectionStart - startno, 1).ToString().Trim().Equals(string.Empty))
  14:                  {
  15:                      strName = rtxtExpression.Text.Substring(rtxtExpression.SelectionStart - startno, startno).Trim();
  16:   
  17:                      break;
  18:                  }
  19:                  startno++;
  20:              }
  21:              if (strName.Equals(string.Empty))
  22:              {
  23:                  return false;
  24:              }
  25:              FCNExpression f = ListFCN.Find((x) => x.ClassCNName.Equals(strName));
  26:              if (f == null)
  27:              {
  28:                  return false;
  29:              }
  30:              foreach (var item in f.InnerExpressions)
  31:              {
  32:                  LstBoxintelli.Items.Add(item.sCnName);
  33:   
  34:              }
  35:              return true;
  36:          }

总结

  我们可以通过Attribute做到很多事情,这次在文中只写出了如果通过Attribute去获取类库的属性名,做出了中英文对应的字典,并在输入点的时候弹出ListBox显示这些属性。下次会写到基于这个功能完成一些基本的判断式和计算式。依然是用中文显示作为输入手段。