I'm using reflection to print out a method signature, e.g.
foreach (var pi in mi.GetParameters()) {
Console.WriteLine(pi.Name + ": " + pi.ParameterType.ToString());
}
This works pretty well, but it prints out the type of primitives as "System.String" instead of "string" and "System.Nullable`1[System.Int32]" instead of "int?". Is there a way to get the name of the paramete开发者_开发技巧r as it looks in code, e.g.
public Example(string p1, int? p2)
prints
p1: string
p2: int?
instead of
p1: System.String
p2: System.Nullable`1[System.Int32]
EDIT: I was half wrong in the answer below.
Have a look at CSharpCodeProvider.GetTypeOutput
. Sample code:
using Microsoft.CSharp;
using System;
using System.CodeDom;
class Test
{
static void Main()
{
var compiler = new CSharpCodeProvider();
// Just to prove a point...
var type = new CodeTypeReference(typeof(Int32));
Console.WriteLine(compiler.GetTypeOutput(type)); // Prints int
}
}
However, this doesn't translate Nullable<T>
into T?
- and I can't find any options which would make it do so, although that doesn't mean such an option doesn't exist :)
There's nothing in the framework to support this - after all, they're C#-specific names.
(Note that string
isn't a primitive type, by the way.)
You'll have to do it by spotting Nullable`1
yourself (Nullable.GetUnderlyingType
may be used for this, for example), and have a map from the full framework name to each alias.
This question has two interesting answers. The accepted one from Jon Skeet pretty much says what he said already.
EDIT Jon updated his answer so its pretty much the same as mine is now. (But of course 20 secs earlier)
But Luke H also gives this answer which I thought was pretty awesome use of the CodeDOM.
Type t = column.DataType; // Int64
StringBuilder sb = new StringBuilder();
using (StringWriter sw = new StringWriter(sb))
{
var expr = new CodeTypeReferenceExpression(t);
var prov = new CSharpCodeProvider();
prov.GenerateCodeFromExpression(expr, sw, new CodeGeneratorOptions());
}
Console.WriteLine(sb.ToString()); // long
Not the most beautiful code in the world, but this is what I ended up doing: (building on Cornard's code)
public static string CSharpName(this Type type)
{
if (!type.FullName.StartsWith("System"))
return type.Name;
var compiler = new CSharpCodeProvider();
var t = new CodeTypeReference(type);
var output = compiler.GetTypeOutput(t);
output = output.Replace("System.","");
if (output.Contains("Nullable<"))
output = output.Replace("Nullable","").Replace(">","").Replace("<","") + "?";
return output;
}
Another option, based on the other answers here.
Features:
- Convert
String
tostring
andInt32
toint
etc - Deal with
Nullable<Int32>
asint?
etc - Suppress
System.DateTime
to beDateTime
- All other types are written in full
It deals with the simple cases I needed, not sure if it will handle complex types well..
Type type = /* Get a type reference somehow */
var compiler = new CSharpCodeProvider();
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
{
return compiler.GetTypeOutput(new CodeTypeReference(type.GetGenericArguments()[0])).Replace("System.","") + "?";
}
else
{
return compiler.GetTypeOutput(new CodeTypeReference(type)).Replace("System.","");
}
No. string
is just a representation of System.String
-- string
doesn't really mean anything behind the scenes.
By the way, to get past System.Nullable'1[System.Int32]
, you can use Nullable.GetUnderlyingType(type);
Here's what I came up with after ~5 mins of hacking. For example:
CSharpAmbiance.GetTypeName(typeof(IDictionary<string,int?>))
will return System.Collections.Generic.IDictionary<string, int?>
.
public static class CSharpAmbiance
{
private static Dictionary<Type, string> aliases =
new Dictionary<Type, string>();
static CSharpAmbiance()
{
aliases[typeof(byte)] = "byte";
aliases[typeof(sbyte)] = "sbyte";
aliases[typeof(short)] = "short";
aliases[typeof(ushort)] = "ushort";
aliases[typeof(int)] = "int";
aliases[typeof(uint)] = "uint";
aliases[typeof(long)] = "long";
aliases[typeof(ulong)] = "ulong";
aliases[typeof(char)] = "char";
aliases[typeof(float)] = "float";
aliases[typeof(double)] = "double";
aliases[typeof(decimal)] = "decimal";
aliases[typeof(bool)] = "bool";
aliases[typeof(object)] = "object";
aliases[typeof(string)] = "string";
}
private static string RemoveGenericNamePart(string name)
{
int backtick = name.IndexOf('`');
if (backtick != -1)
name = name.Substring(0, backtick);
return name;
}
public static string GetTypeName(Type type)
{
if (type == null)
throw new ArgumentNullException("type");
string keyword;
if (aliases.TryGetValue(type, out keyword))
return keyword;
if (type.IsArray) {
var sb = new StringBuilder();
var ranks = new Queue<int>();
do {
ranks.Enqueue(type.GetArrayRank() - 1);
type = type.GetElementType();
} while (type.IsArray);
sb.Append(GetTypeName(type));
while (ranks.Count != 0) {
sb.Append('[');
int rank = ranks.Dequeue();
for (int i = 0; i < rank; i++)
sb.Append(',');
sb.Append(']');
}
return sb.ToString();
}
if (type.IsGenericTypeDefinition) {
var sb = new StringBuilder();
sb.Append(RemoveGenericNamePart(type.FullName));
sb.Append('<');
var args = type.GetGenericArguments().Length - 1;
for (int i = 0; i < args; i++)
sb.Append(',');
sb.Append('>');
return sb.ToString();
}
if (type.IsGenericType) {
if (type.GetGenericTypeDefinition() == typeof(Nullable<>))
return GetTypeName(type.GetGenericArguments()[0]) + "?";
var sb = new StringBuilder();
sb.Append(RemoveGenericNamePart(type.FullName));
sb.Append('<');
var args = type.GetGenericArguments();
for (int i = 0; i < args.Length; i++) {
if (i != 0)
sb.Append(", ");
sb.Append(GetTypeName(args[i]));
}
sb.Append('>');
return sb.ToString();
}
return type.FullName;
}
}
精彩评论