共享一个从字符串转 Lambda 表达式的类(3)
承上篇的思路继续写,这次介绍字符串转 Type 的方式——类型分析。我的思路是把 Type 解析由“TestNet.Person, TestNet, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null” 这种复杂的方式改为 “Person” 这种。这样,写起来简单明了,看起来也简单明了。
这次要说的东西比较简单,我借用一个例子说明:
首先,字符串“TestNet.Person”经过解析被分析为下面的 Token 集合:
- 标识、索引值 = 0、文本表示 = TestNet
- 句点、索引值 = 7、文本表示 = .
- 标识、索引值 = 8、文本表示 = Person
接着,判断标识符是否等于 int、bool 等 C# 基本类型文本名称,是则返回相应的类型( Type 实例);否则借用 Type.GetType 方法解析,进一步借用 Assembly.GetType 方法解析:
- 判断 TestNet 不是 int、bool 等 C# 基本类型的文本名称。
- 借用 Type.GetType 方法解析,返回值为 null 。
- 进一步借用 Assembly.GetType 方法解析,返回值为 null 。
- 读取下一个字符 ID = 句点,表示 TestNet 可能是命名空间名称,需要继续读取并分析。
- 判断 TestNet.Person 不是 int、bool 等 C# 基本类型的文本名称。
- 借用 Type.GetType 方法解析,返回值为 null 。
- 进一步借用 Assembly.GetType 方法解析,返回值为 TestNet.Person 类型的 Type 实例。
- 分析过程结束。
实际的过程中,我们还需要为分析方法添加额外的命名空间。这样,像“TestNet.Person” 这样的类型,就可以简写为 “Person”,符合我们使用 C# 的编码规范。
进一步考虑,我们可以从项目未引用的程序集中提取类型,这时候需要添加额外的 Assembly 。这样做的好处是:可以在不编译整个项目的情况下,更改某个配置,就可以使用新的程序集,新的逻辑。呵呵,是不是有点插件式编程的影子了。下一篇,应该会揭开面纱了。
下面,我给出类型解析类(TypeParser)的源码:
/// <summary>
/// 类型分析器
/// </summary>
[DebuggerStepThrough]
public class TypeParser
{
#region Properties
/// <summary>
/// 原始字符串分析结果
/// </summary>
private SymbolParseResult spResult = null;
/// <summary>
/// 获得待分析的类型可能用到的命名空间列表
/// </summary>
private IEnumerable<string> namespaces = Enumerable.Empty<string>();
/// <summary>
/// 获得额外的程序集信息列表
/// </summary>
private IEnumerable<Assembly> assemblyExtensions = Enumerable.Empty<Assembly>();
private TypeParser()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="TypeParser"/> class.
/// </summary>
/// <param name="spResult">The symbol parse result.</param>
internal TypeParser(ref SymbolParseResult spResult)
{
this.spResult = spResult;
}
/// <summary>
/// 获得一个 <see cref="TypeParser"/> 类的实例对象
/// </summary>
public static TypeParser NewInstance
{
get { return new TypeParser(); }
}
private static Assembly[] _assemblies = null;
/// <summary>
/// 获取程序入口点所在目录程序集列表
/// </summary>
private static Assembly[] Assemblies
{
get
{
if (_assemblies == null)
{
var directory = string.Empty;
var assembly = Assembly.GetEntryAssembly();
if (assembly != null)
directory = Path.GetDirectoryName(assembly.Location);
else
directory = AppDomain.CurrentDomain.BaseDirectory;
var files = Directory.GetFiles(directory, "*.dll", SearchOption.TopDirectoryOnly);
var data = new List<Assembly>(files.Length);
foreach (var item in files)
{
try
{
data.Add(Assembly.LoadFile(item));
}
catch { }
}
_assemblies = data.ToArray();
}
return _assemblies;
}
}
#endregion
#region Business Methods
/// <summary>
/// 添加可能遇到的命名空间字符串列表
/// </summary>
/// <param name="namespaces">新的命名空间字符串列表</param>
/// <returns>修改后的自身</returns>
public TypeParser SetNamespaces(IEnumerable<string> namespaces)
{
this.namespaces = namespaces ?? Enumerable.Empty<string>();
return this;
}
/// <summary>
/// 添加可能遇到的命名空间字符串列表
/// </summary>
/// <param name="namespaces">新的命名空间字符串列表</param>
/// <returns>修改后的自身</returns>
public TypeParser SetNamespaces(params string[] namespaces)
{
this.namespaces = namespaces ?? Enumerable.Empty<string>();
return this;
}
/// <summary>
/// 添加可能遇到的程序集信息列表
/// </summary>
/// <param name="assemblies">附加的程序集信息列表</param>
/// <returns>修改后的自身</returns>
public TypeParser SetAssemblies(IEnumerable<Assembly> assemblies)
{
assemblyExtensions = assemblies ?? Enumerable.Empty<Assembly>();
return this;
}
/// <summary>
/// 添加可能遇到的程序集信息列表
/// </summary>
/// <param name="assemblies">附加的程序集信息列表</param>
/// <returns>修改后的自身</returns>
public TypeParser SetAssemblies(params Assembly[] assemblies)
{
assemblyExtensions = assemblies ?? Enumerable.Empty<Assembly>();
return this;
}
/// <summary>
/// 解析字符串为类型
/// </summary>
/// <returns>读取的类型</returns>
public Type Resolve(string typeString)
{
spResult = SymbolParser.Build(typeString);
return ReadType();
}
#endregion
#region Private Methods
internal Type ReadType(string typeName = null, bool ignoreException = false)
{
Type type = null;
StringBuilder sbValue =
new StringBuilder(string.IsNullOrEmpty(typeName) ? spResult.Next() : typeName);
do
{
// read generic parameters
if (spResult.PeekNext() == "<")
{
spResult.Skip();
List<Type> listGenericType = new List<Type>();
while (true)
{
listGenericType.Add(ReadType());
if (spResult.PeekNext() == ",")
spResult.Skip();
else
break;
}
NextIsEqual(">");
sbValue.AppendFormat("`{0}[{1}]", listGenericType.Count,
string.Join(",", listGenericType
.Select(p => "[" + p.AssemblyQualifiedName + "]").ToArray()));
}
type = GetType(sbValue.ToString());
if (type == null)
{
bool result = NextIsEqual(".", false);
if (!result)
{
if (ignoreException)
break;
throw new ParseUnfindTypeException(sbValue.ToString(), spResult.Index);
}
sbValue.Append(".");
sbValue.Append(spResult.Next());
}
} while (type == null);
return type;
}
internal Type GetType(string typeName)
{
if (string.IsNullOrEmpty(typeName))
return null;
// Nullable
bool isNullable = false;
if (typeName.EndsWith("?"))
{
isNullable = true;
typeName = typeName.Substring(0, typeName.Length - 1);
}
Type type;
switch (typeName)
{
case "bool":
type = typeof(bool);
break;
case "byte":
type = typeof(byte);
break;
case "sbyte":
type = typeof(sbyte);
break;
case "char":
type = typeof(char);
break;
case "decimal":
type = typeof(decimal);
break;
case "double":
type = typeof(double);
break;
case "float":
type = typeof(float);
break;
case "int":
type = typeof(int);
break;
case "uint":
type = typeof(uint);
break;
case "long":
type = typeof(long);
break;
case "ulong":
type = typeof(ulong);
break;
case "object":
type = typeof(object);
break;
case "short":
type = typeof(short);
break;
case "ushort":
type = typeof(ushort);
break;
case "string":
type = typeof(string);
break;
default:
{
// Suppose typeName is full name of class
type = GetTypeCore(typeName);
// Did not find the namespace to use all of the match again and again
if (type == null)
{
foreach (string theNamespace in namespaces)
{
type = GetTypeCore(string.Concat(theNamespace, ".", typeName));
// To find a qualified first class
if (type != null)
break;
}
}
}
break;
}
if (isNullable && type != null)
type = typeof(Nullable<>).MakeGenericType(type);
return type;
}
private Type GetTypeCore(string typeName)
{
Type type = Type.GetType(typeName);
if (type != null)
return type;
Assembly[] listAssembly = AppDomain.CurrentDomain.GetAssemblies();
foreach (Assembly assembly in listAssembly)
{
type = assembly.GetType(typeName, false, false);
if (type != null)
return type;
}
if (assemblyExtensions != null && assemblyExtensions.Any())
{
foreach (Assembly assembly in assemblyExtensions)
{
type = assembly.GetType(typeName, false, false);
if (type != null)
return type;
}
}
if (Assemblies != null && Assemblies.Any())
{
foreach (Assembly assembly in Assemblies)
{
type = assembly.GetType(typeName, false, false);
if (type != null)
return type;
}
}
return null;
}
private bool NextIsEqual(string symbol, bool throwExceptionIfError = true)
{
if (spResult.Next() != symbol)
{
if (throwExceptionIfError)
throw new ApplicationException(string.Format("{0} isn't the next token", symbol));
else
return false;
}
return true;
}
#endregion
}
使用到的一个异常类如下:
/// <summary>
/// Parse UnfindType Exception
/// </summary>
[Serializable]
[DebuggerStepThrough]
public class ParseUnfindTypeException : Exception
{
/// <summary>
/// Initializes a new instance of the <see cref="ParseUnfindTypeException"/> class.
/// </summary>
/// <param name="typeName">Name of the type.</param>
/// <param name="errorIndex">Index of the error.</param>
public ParseUnfindTypeException(string typeName, int errorIndex)
: base(string.Format("{0} in the vicinity of the type \"{1}\" not found", errorIndex, typeName))
{
}
}
需要注意的是,这个类用到了上次提到的字符串解析结果,需要两者相互配合。嘿嘿,再给个示意图诱惑一下:
如果您感觉有用,顺手点下推荐,谢了!
转载于:https://www.cnblogs.com/lenic/archive/2012/06/05/2536156.html
共享一个从字符串转 Lambda 表达式的类(3)相关推荐
- 共享一个从字符串转 Lambda 表达式的类(4)
开始写第四篇,别的不说了.这篇将涉及到如何使用字符串解析结果,生成一个 Lambda 表达式树.东西有点多,我先整理一下思路,在下面说明一下.如果你有问题,在后面的评论上写下来,我看到了会回复你. 在 ...
- 拼接 字符串使用 Lambda 表达式
拼接 字符串 String value = memberRankList.stream().map(MemberRanking -> MemberRanking.getRowIndex().to ...
- Java8 Lambda 表达式官方文档
本文是对官方文档的不完全翻译,如有错误请指正. Lambda 表达式 匿名类的实现非常简单,例如只包含一个方法的接口,在这些情况下,您通常会尝试将函数作为参数传递给另一个方法,例如当有人单击按钮时应采 ...
- Java8 Lambda表达式语法和示例
本文是对官方文档(https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html)的概括总结,更详细的内容请看官方 ...
- Java学习记录五(多线程、网络编程、Lambda表达式和接口组成更新)
Java学习记录五(多线程.网络编程.Lambda表达式和接口组成更新) Java 25.多线程 25.1实现多线程 25.1.1进程 25.1.2线程 25.1.3多线程的实现 25.1.4设置和获 ...
- java 8 lambda reduce_JDK8新特性Lambda表达式体验
"Lambda 表达式"(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstra ...
- 10个Java 8 Lambda表达式经典示例
Java 8 刚于几周前发布,日期是2014年3月18日,这次开创性的发布在Java社区引发了不少讨论,并让大家感到激动.特性之一便是随同发布的lambda表 达式,它将允许我们将行为传到函数里.在J ...
- Java Lambda表达式入门
本文转自:http://blog.csdn.net/renfufei... 转载请注明出处 原文链接: Start Using Java Lambda Expressions 下载示例程序 Examp ...
- java拉姆达表达式事例,Java Lambda表达式详解和实例
简介 Lambda表达式是Java SE 8中一个重要的新特性.lambda表达式允许你通过表达式来代替功能接口. lambda表达式就和方法一样,它提供了一个正常的参数列表和一个使用这些参数的主体( ...
最新文章
- Javascript函数执行、new机制以及继承
- html5初探ppt,HTML5---HTML5初探151019解析.ppt
- NoSQL有了Android版本
- 交叉熵损失函数分类_交叉熵损失函数
- 民生银行场景化数据中台是如何炼成的?
- NSString的各种用法总结(创建、截取、判断比较、转化数据类型、拼接、替换、添加、追加、读取、写入、删去、改变)
- linux 下脚本安装 mysql_linux(centos7)下编译安装mysql(数据库)一键安装详解+脚本文件...
- mysql jion 三张_mysql三张表 left join
- pytorch分布式训练(二):torch.nn.parallel.DistributedDataParallel
- 网络编程之 osi七层协议
- 深圳90后小伙拿到14所国外名牌大学offer
- Centos6.5 x86_64系统安装kvm虚拟机—基础篇
- PKM全民推广系列二:PKM活动(过程)
- 三菱Q系列PLC大型程序Q01U伺服12轴 实际使用中程序
- python scipy拟合曲线optimize.curve_fit 50例
- 在小程序可以完成任务的情况下,为什么程序员非要编写大程序呢?
- 国内TCP单边“加速”的“正确”做法
- CAD编辑指南7:新建空白图纸和新建表格、导入图片
- Win10_此电脑_多余项目设备和驱动器
- 校招信息可以看哪些网站