我正在编写一个简单的代码生成应用程序,以从 DB2 数据库模式构建 POCO。 我知道这并不重要,但我更喜欢使用类型别名而不是实际的系统类型名称(如果可用),即“int”而不是“Int32”。 有没有一种方法可以使用反射来获取类型的别名而不是实际类型?
//Get the type name
var typeName = column.DataType.Name;
//If column.DataType is, say, Int64, I would like the resulting property generated
//in the POCO to be...
public long LongColumn { get; set; }
//rather than what I get now using the System.Reflection.MemberInfo.Name property:
public Int64 LongColumn { get; set; }
不 - 只需创建一个
Dictionary<Type,string>
将所有类型映射到它们的别名。这是一个固定的集合,所以并不难做到:
private static readonly Dictionary<Type, string> Aliases =
new Dictionary<Type, string>()
{
{ typeof(byte), "byte" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(int), "int" },
{ typeof(uint), "uint" },
{ typeof(long), "long" },
{ typeof(ulong), "ulong" },
{ typeof(nint), "nint" },
{ typeof(nuint), "nuint" },
{ typeof(float), "float" },
{ typeof(double), "double" },
{ typeof(decimal), "decimal" },
{ typeof(object), "object" },
{ typeof(bool), "bool" },
{ typeof(char), "char" },
{ typeof(string), "string" },
{ typeof(void), "void" }
};
严格来说,这不使用反射,但您可以使用 CodeDOM 获取类型的别名:
Type t = column.DataType; // Int64
string typeName;
using (var provider = new CSharpCodeProvider())
{
var typeRef = new CodeTypeReference(t);
typeName = provider.GetTypeOutput(typeRef);
}
Console.WriteLine(typeName); // long
(话虽如此,我认为建议您只使用从 CLR 类型到 C# 别名的映射的其他答案可能是使用此答案的最佳方法。)
如果有人需要带有可空值的字典:
private static readonly Dictionary<Type, string> Aliases = new Dictionary<Type, string>()
{
{ typeof(byte), "byte" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(int), "int" },
{ typeof(uint), "uint" },
{ typeof(long), "long" },
{ typeof(ulong), "ulong" },
{ typeof(float), "float" },
{ typeof(double), "double" },
{ typeof(decimal), "decimal" },
{ typeof(object), "object" },
{ typeof(bool), "bool" },
{ typeof(char), "char" },
{ typeof(string), "string" },
{ typeof(void), "void" },
{ typeof(Nullable<byte>), "byte?" },
{ typeof(Nullable<sbyte>), "sbyte?" },
{ typeof(Nullable<short>), "short?" },
{ typeof(Nullable<ushort>), "ushort?" },
{ typeof(Nullable<int>), "int?" },
{ typeof(Nullable<uint>), "uint?" },
{ typeof(Nullable<long>), "long?" },
{ typeof(Nullable<ulong>), "ulong?" },
{ typeof(Nullable<float>), "float?" },
{ typeof(Nullable<double>), "double?" },
{ typeof(Nullable<decimal>), "decimal?" },
{ typeof(Nullable<bool>), "bool?" },
{ typeof(Nullable<char>), "char?" }
};
基于上述 2 个使用字典的答案,我编写了 2 个基本扩展方法,可能有助于清理使用。在您的项目中包含此类,您只需调用类型上的 Alias() 或 AliasOrName() 方法即可使用它,如下所示。
使用示例;
// returns int
string intAlias = typeof(Int32).Alias();
// returns int
string intAliasOrName = typeof(Int32).AliasOrName();
// returns string.empty
string dateTimeAlias = typeof(DateTime).Alias();
// returns DateTime
string dateTimeAliasOrName = typeof(DateTime).AliasOrName();
实施;
public static class TypeExtensions
{
public static string Alias(this Type type)
{
return TypeAliases.ContainsKey(type) ?
TypeAliases[type] : string.Empty;
}
public static string AliasOrName(this Type type)
{
return TypeAliases.ContainsKey(type) ?
TypeAliases[type] : type.Name;
}
private static readonly Dictionary<Type, string> TypeAliases = new Dictionary<Type, string>
{
{ typeof(byte), "byte" },
{ typeof(sbyte), "sbyte" },
{ typeof(short), "short" },
{ typeof(ushort), "ushort" },
{ typeof(int), "int" },
{ typeof(uint), "uint" },
{ typeof(long), "long" },
{ typeof(ulong), "ulong" },
{ typeof(float), "float" },
{ typeof(double), "double" },
{ typeof(decimal), "decimal" },
{ typeof(object), "object" },
{ typeof(bool), "bool" },
{ typeof(char), "char" },
{ typeof(string), "string" },
{ typeof(void), "void" },
{ typeof(byte?), "byte?" },
{ typeof(sbyte?), "sbyte?" },
{ typeof(short?), "short?" },
{ typeof(ushort?), "ushort?" },
{ typeof(int?), "int?" },
{ typeof(uint?), "uint?" },
{ typeof(long?), "long?" },
{ typeof(ulong?), "ulong?" },
{ typeof(float?), "float?" },
{ typeof(double?), "double?" },
{ typeof(decimal?), "decimal?" },
{ typeof(bool?), "bool?" },
{ typeof(char?), "char?" }
};
}
public string GetAlias(Type t)
{
string typeName = "";
using (var provider = new CSharpCodeProvider())
{
var typeRef = new CodeTypeReference(t);
typeName = provider.GetTypeOutput(typeRef);
}
return typeName;
}
保持简单:
var aliasDict = new Dictionary<Type, string>() {
{ typeof(int), "int" },
{ typeof(long), "long" },
// etc
}
Type reflectedType;
string aliasedTypeName = aliasDict[reflectedType];
我认为没有。 别名完全是一个特定于您使用的特定 .NET 语言的编译时概念。 一旦您反映并查看类型,您将看到对象的真实 .NET 类型。
字典的答案很灵活,但如果我们只想要基本类型,我们可以做得更好:
public static class TypeNameExtensions
{
private static readonly string[] TypeAliases = {
"void", // 0
null, // 1 (any other type)
"DBNull", // 2
"bool", // 3
"char", // 4
"sbyte", // 5
"byte", // 6
"short", // 7
"ushort", // 8
"int", // 9
"uint", // 10
"long", // 11
"ulong", // 12
"float", // 13
"double", // 14
"decimal", // 15
null, // 16 (DateTime)
null, // 17 (-undefined- presumably TimeSpan in some pre-1.0 C# alpha)
"string", // 18
};
如果不需要支持数组类型:
public static bool TryGetNameAlias(this Type t, out string alias)
=> (alias = TypeAliases[(int)Type.GetTypeCode(t)]) != null && !t.IsEnum;
编辑:如果需要支持数组类型:
public static bool TryGetNameAlias(this Type t, out string alias)
{
string arrayBrackets = null;
while (t.IsArray)
{
arrayBrackets += "[" + new string(',', t.GetArrayRank() - 1) + "]";
t = t.GetElementType();
}
alias = TypeAliases[(int)Type.GetTypeCode(t)];
if (alias == null || t.IsEnum)
return false;
alias += arrayBrackets;
return true;
}
}
这是基于
TypeCode
枚举:应该比字典更快,因为它使用 TypeCode 作为索引直接跳转到数组中。
唯一的缺点是,如果我们想将
Object
别名为 object
,我们需要额外检查。
如果您想知道 为什么 这个枚举存在,它用于促进
System.IConvertible
的高性能实现 - 也公开了 GetTypeCode()
方法:因此,从本质上讲,它可以被视为原始 C# 开发团队中的某人在 v1.1 时代出于某种原因决定公开的实现细节。也许这样,如果其他人也需要对内置类型进行高性能摆弄,他们就可以利用它?
无论如何,它从早期就已经成为该语言的一部分,至今已有 20 多年了! :D
(就我个人而言,我利用
TypeCode
构建了一个小型库,用于通用数值范围检查和其他特定于数字的元数据方法,例如使用编译时未知的通用数值类型执行算术,而不使用反射或 try-catch 尝试。 )
编辑:更新为支持数组类型(包括嵌套和多维)。
编辑:更新以正确处理
enum
类型。