【发布时间】:2010-08-29 06:49:40
【问题描述】:
我有一个字符串,例如“Int”、“Double”、“DateTime”等。如何从该字符串中获取完全限定名称?
【问题讨论】:
-
为什么需要全限定名?也许如果您提供一些额外的信息,我们可以提供更好的答案。
我有一个字符串,例如“Int”、“Double”、“DateTime”等。如何从该字符串中获取完全限定名称?
【问题讨论】:
值得注意的是int 不是一个类型。它是 C# 为类型 System.Int32 提供的别名。牢记这一点,并假设您只关心核心类型,您可以尝试:
var typeName = "DateTime";
var systemTypesAssembly = Assembly.Load("mscorlib");
var type = (from t in systemTypesAssembly.GetTypes()
where t.Name == typeName
select t).FirstOrDefault();
Console.WriteLine(type.FullName);
正如我所说,这不会适用于Int,但适用于Int32,这是它的别名类型。 此代码也不包含错误处理,例如,在 mscorlib 中找不到与您在typeName中输入的类型匹配的类型
【讨论】:
type 是否为空时,通常最好使用 .First(),因为它会立即抛出一个有意义的异常,而不是稍后抛出一个无意义的 NullReferenceException .
在进一步讨论之前,我想指出 .NET Framework 基类库中没有名为 Int 的类。有System.Int32,在C#中恰好有一个别名:int。
您可以通过多种方式做到这一点。
一种简单但有限的方法是使用字典将字符串映射到相应的 FQN:
public static IDictionary<string, string> FqnMap = new Dictionary<string, string>
{
{ "Int", "System.Int32" },
{ "Double", "System.Double" },
{ "DateTime", "System.DateTime" },
};
public string GetFqn(string name)
{
return FqnMap[name]; // TODO: add error handling
}
一种更复杂但更强大的方法是使用reflection 从一组程序集中搜索所有类型。像这样的:
public class FqnResolver
{
public FqnResolver(IEnumerable<Assembly> assemblies)
{
Assemblies = new List<Assembly>(assemblies);
}
public FqnResolver(params Assembly[] assemblies) : this(assemblies as IEnumerable<Assembly>) { }
public FqnResolver() : this(new Assembly[0]) { }
public ICollection<Assembly> Assemblies { get; private set; }
public string GetFqn(string name)
{
var candidates = from a in Assemblies
from t in a.GetTypes()
where t.Name == name
select t.FullName;
return candidates.First(); // will throw if no valid type was found
// and does not count duplicates
}
}
【讨论】:
这在 .Net 中并不是真正可行的。为了获得一个类型的完全限定名称,您需要方便地使用Type 对象。为了获得Type 对象,您通常需要一个实例、完全限定名称,或者您必须进行一些搜索。
后者有效,但效率不高,因为您需要搜索每个程序集并输入已加载的 AppDomain 以找到正确答案。
foreach ( var assembly in AppDommain.CurrentDomain.GetAssemblies() ) {
foreach ( var type in assembly.GetTypes() ) {
if ( type.Name == target ) {
return type.FullName;
}
}
}
尽管如此,此解决方案仍不能 100% 为您工作。主要是因为 .Net 框架中没有类型“Int”。它的实际类型名称是“Int32”。
【讨论】:
像“String”这样的类型名称可能不明确,因为它可能引用System.String 或FooAssembly.String,因此您必须搜索所有已加载程序集中的所有类型,这可能会产生多个结果。这一点反射可能很慢,但您可以以内存为代价进行缓存结果的明显优化:
static void Main(string[] args)
{
string typeName = "String";
foreach (var type in GetFullType(typeName))
{
Console.WriteLine(type.FullName);
}
}
static IEnumerable<Type> GetFullType(string className)
{
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
{
foreach (var type in assembly.GetTypes())
{
if (type.Name.Equals(className, StringComparison.OrdinalIgnoreCase))
{
yield return type;
}
}
}
}
【讨论】: