C#get null对象的类型

63 c#

我有C#方法

private static string TypeNameLower(object o)
{
   return o.GetType().Name.ToLower();
}
Run Code Online (Sandbox Code Playgroud)

给我输入对象的小写类型名称.

但是如果input是一个设置为null的字符串或者设置为null的nullable int,那么这个方法当然会失败.

在这种情况下如何获取类型名称?

Jos*_*osh 66

杰夫是对的.这就像问一个没有标签的空盒子里会有什么样的蛋糕.

作为Fortran答案的替代方案,您还可以:

string TypeNameLower<T>(T obj) {
   return typeof(T).Name.ToLower(CultureInfo.InvariantCulture);
}

string TypeNameLower(object obj) {
   if (obj != null) { return obj.GetType().Name.ToLower(CultureInfo.InvariantCulture); }
   else { return null; }
}

string s = null;
TypeNameLower(s); // goes to the generic version
Run Code Online (Sandbox Code Playgroud)

这样,C#将在编译时选择通用的,如果它对你传入的类型有足够的了解.

  • "这就像问一个没有标签的空盒子里会有什么样的蛋糕." 等等,我知道答案.这是一次测试.只要你不打开盒子,盒子不会同时包含蛋糕而不是蛋糕吗? (9认同)
  • 请注意,此方法提供了传递的表达式的_compile-time type_(也称为_declared_类型).这通常不同于运行时类型(程序运行时对象实例的实际类型).因此,在许多情况下,问题的方法不会抛出,这两种方法不一致.举个例子,考虑变量`ICloneable c ="hello";`问题的方法会返回`typeof(string)`,而这个答案的方法,调用为`TypeNameLower(c)`返回`typeof(ICloneable) )`. (5认同)
  • 我想我正在寻找的答案是,即使我告诉编译器我打算填充变量的类型,然后如果该变量设置为null,我无法检索预期的类型. (4认同)

drw*_*ode 36

我想我会发布我的答案,即使这个问题已经过时了,因为在我看来,接受的答案是错误的.这个答案很有创意,所以我不是故意要敲门.据我所知,这可能是OP真正想要的.

但是,正如您将从下面的示例中看到的那样,我认为在几乎所有情况下,使用接受答案中描述的通用函数的想法是(A)不必要或(B)完全错误.我已经从接受的答案中复制了我正在谈论的通用功能,并将其粘贴在下面以供参考:

string TypeNameLower<T>(T obj) {
    return typeof(T).Name.ToLower();
}
Run Code Online (Sandbox Code Playgroud)

现在,让我们看看可以使用此函数的一些方法:

通用功能不必要的示例:

var s = "hello";
var t = TypeNameLower(s);

//or
foreach(char c in "banana")
    WriteLine(TypeNameLower(c));

//or
foreach(MyCustomStruct x in listOfMyCustomStruct)
    WriteLine(TypeNameLower(x));
Run Code Online (Sandbox Code Playgroud)

在这些示例中,函数可以工作 - 也就是说,它确实返回正确的值,分别是"string","char"和"mycustomstruct".但是在所有这些情况下(即泛型函数确实返回正确的类型),编译器提前知道变量的定义类型是什么,当然程序员也是如此(除非他们对此感到困惑)他们的变量名称).所以这个函数是完全没必要的,程序员也可以这样做:

var s = "hello";
var t = "string";

//or
foreach(char c in "banana")
    WriteLine("char");

//or
foreach(MyCustomStruct x in listOfMyCustomStruct)
    WriteLine("mycustomstruct");
Run Code Online (Sandbox Code Playgroud)

这听起来有点幼稚,但仔细想想一会儿......它真的在...尝试拿出其中在使用通用功能提供准确信息的情况下击沉可能需要一段时间,运行时与工作不"T已知的(并且因此可以是自动生成的编译器或代码生成工具如T4模板)在编译时.

现在,上一组示例的目的只是为了演示泛型函数的一个小麻烦 - 在每种情况下它都不需要返回正确的结果.但更重要的是,请看下面的示例.他们演示了在任何其他情况下,如果您希望函数返回对象的真实运行时类型的名称,则泛型函数的结果实际上是错误的.实际上,该函数保证返回真值可分配的类型的名称,该类型可能是祖先类,接口或"对象"本身.

通用功能错误的示例

Stream ms = new MemoryStream();
IEnumerable str = "Hello";
IComparable i = 23;
object j = 1;

TypeNameLower(ms); //returns "stream" instead of "memorystream"
TypeNameLower(str); //returns "ienumerable" instead of "string"
TypeNameLower(i); //returns "icomparable" instead of "int32"
TypeNameLower(j); //returns "object" instead of "int32"
TypeNameLower<object>(true); //returns "object" instead of "bool"
Run Code Online (Sandbox Code Playgroud)

在所有情况下,结果都是错误的,你可以看到.现在,我承认最后两行有点用来证明这一点(更不用说TypeNameLower(j)实际上会被编译为使用函数的非泛型版本,这也是已接受答案的一部分 - 但是你得到了理念...)

问题是该函数实际上忽略了传入的对象的类型,并且仅使用泛型参数类型的(编译时)信息来返回该值.

更好的实施方式如下:

string TypeNameLower<T>(T obj) {
    Type t;
    if (obj == null)
        t = typeof(T);
    else 
        t = obj.GetType();
    return t.Name.ToLower();
}
Run Code Online (Sandbox Code Playgroud)

现在,只要对象为非null,函数就会返回真实运行时类型的名称,当类型为时,它默认为编译时/定义类型null.

重要的是,这个功能可以在没有非通用版本的情况下使用!! 结果是函数永远不会返回null.最常见的返回值是"对象",例如:

 object x = null; 
 string s = null;
 byte[] b = null;
 MyClass m = null;
 TypeNameLower(x); // returns "object"
 TypeNameLower(s); // returns "string"
 TypeNameLower(b); // returns "byte[]"
 TypeNameLower(m); // returns "myclass"
Run Code Online (Sandbox Code Playgroud)

请注意,这实际上与OP所要求的功能的定义目标更加一致.也就是说,如果OP 确实想要找出对象的类型名称是什么,如果它不是null,那么返回null将永远不是一个合适的答案,因为null不是任何Type的名称,并且typeof(null)未定义.

在C#中每个变量下降的System.Object,因此按照定义,如果该值不是null那么它是一个Object,那就是在许多情况下,可在运行时一个空引用来确定最.

  • 所以我同意你写的几乎所有内容.但是,对于_"尝试提出任何使用泛型函数的方案,在运行时提供尚未知的准确信息(因此可以由编译器或代码生成实用程序(如T4模板)自动生成),编译时."_如果你试图在另一个泛型函数中使用TypeNameLower,那么类型基本上是由编译器知道的,而不是程序员知道的,所以你的硬字符串解决方案就像`foreach(char c in"banana") )WriteLine("char");`似乎不合理. (2认同)

her*_*ter 19

// Uses the compiler's type inference mechanisms for generics to find out the type
// 'self' was declared with in the current scope.
static public Type GetDeclaredType<TSelf>(TSelf self)
{
    return typeof(TSelf);
}

void Main()
{
    // ...

    Foo bar;
    bar = null;

    Type myType = GetDeclaredType(bar);
    Console.Write(myType.Name);
}
Run Code Online (Sandbox Code Playgroud)

打印:

Foo
Run Code Online (Sandbox Code Playgroud)

我也发布了类似的主题,希望对你有用.;-)


for*_*ran 15

if (o == null) return "null";
else return o.GetType().Name.ToLower();
Run Code Online (Sandbox Code Playgroud)

解决一个简单问题的简单方法:-p


HVS*_*HVS 8

正如其他人所说,你做不到.对于允许对对象进行纯空引用的语言,这实际上是一个众所周知的问题.解决它的一种方法是使用"空对象模式".基本思想是,不是使用null空引用,而是为其分配"不执行任何操作"对象的实例.例如:

public class Circle
{
    public virtual float Radius { get; set; }

    public Circle(float radius)
    {
        Radius = radius;
    }
}

public class NullCircle : Circle
{
    public override float Radius 
    { 
        get { return float.NaN; }
        set { }
    }

    public NullCircle() { }
}
Run Code Online (Sandbox Code Playgroud)

然后,您可以传递NullCircle而不是代码的实例,null您将能够像在代码中一样测试其类型.