C# получить тип нулевого объекта [дубликат]
этот вопрос уже есть ответ здесь:
- .NET: как вы получаете тип нулевого объекта? 12 ответов
У меня есть метод C#
private static string TypeNameLower(object o)
{
return o.GetType().Name.ToLower();
}
чтобы дать мне имя типа нижнего регистра входного объекта.
но если входными данными является строка имеет значение null или интервал nullable установлен в нуль, этот метод, конечно неудачи.
Как получить имя типа в этой ситуации?
11 ответов:
Джефф является правильным. Это все равно что спросить, какой торт был бы в пустой коробке без этикетки.
в качестве альтернативы ответу Фортрана вы также можете сделать:
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
таким образом, C# выберет общий во время компиляции, если он знает достаточно о типе, который вы передаете.
я думал, что опубликую свой ответ, хотя этот вопрос старый, потому что, на мой взгляд, принятый ответ неверен. Этот ответ был довольно творческим, поэтому я не собираюсь его стучать. И насколько я знаю, это может быть тем, что ОП действительно хотел.
но, как вы увидите из моих примеров, я думаю, что почти все случаи, идея использования общей функции, описанной в принятом ответе, либо (а) ненужна, либо (Б) плоская неправильный. Я скопировал общую функцию, о которой я говорю, из принятого ответа и вставил ее ниже Для справки:
string TypeNameLower<T>(T obj) { return typeof(T).Name.ToLower(); }
теперь давайте посмотрим, как эта функция может быть использована:
примеры, когда общая функция не нужна:
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));
в этих примерах функция работает--то есть, она возвращает правильно значения, которые являются "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");
это может показаться наивным на первый взгляд, но подумайте об этом для a while...it может потребоваться некоторое время, чтобы он действительно утонул...Пытаться придумайте любой сценарий, в котором использование универсальной функции предоставляет точную информацию по адресу Runtime это еще не известно (и, следовательно, может быть автоматически сгенерировано компилятором или утилитами генерации кода, такими как шаблоны 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"
во всех случаях результаты совершенно неверны, как вы можете видеть. Теперь я признаю, что последние две строки были немного придуманы, чтобы продемонстрировать точку зрения (не говоря уже о том, что
TypeNameLower(j)
фактически будет скомпилирован для использования неродовой версии функции, которая также является частью принятого ответа-но вы получите идею...)проблема в том, что функция на самом деле игнорирует тип передаваемого объекта и использует только информацию (время компиляции) универсального типа параметра для возврата значения.
лучшей реализацией было бы следующее:
string TypeNameLower<T>(T obj) { Type t; if (obj == null) t = typeof(T); else t = obj.GetType(); return t.Name.ToLower(); }
теперь функция возвращает имя истинного типа времени выполнения всякий раз, когда объект не равен null, и по умолчанию используется тип времени компиляции/defined, когда тип
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"
отметим, что это на самом деле более последовательны с определенными объективными функции, как и просил ОП. То есть, если ОП действительно хочет узнать, что тип-имя объекта было если бы это не было null, то возвращение null никогда не будет подходящим ответ, потому что null-это не имя какого-либо типа, а typeof(null) не определен.
каждая переменная в C# происходит от
System.Object
, так что по определению, если значение неnull
затем б бытьObject
и это во многих случаях максимум, что можно определить о значение null во время выполнения.
// 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); }
принты:
Foo
Я разместил это также в аналогичной теме, я надеюсь, что это будет полезно для вас. ; -)
if (o == null) return "null"; else return o.GetType().Name.ToLower();
простое решение для простой задачи : - p
как другие упоминают, нельзя. На самом деле это хорошо известная проблема с языками, которые позволяют чистым нулем ссылок на объекты. Один из способов обойти это-использовать "шаблон нулевого объекта". Основная идея заключается в том, что вместо использования
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() { } }
затем вы можете передать экземпляр
NullCircle
вместоnull
и вы сможете проверить его тип, как в вашем коде.
насколько мне известно, Вы не можете. Null указывает на отсутствие значения и не отличается для разных типов.
нет понятия, что нулевая строка отличается от нулевого массива отличается от нулевого чего-либо еще. Внутри вашей функции, вы не можете определить имя типа.
более конкретно, экземпляр ссылочного класса (внутренне) включает в себя "указатель" на информацию о типе объекта. Если входное значение равно null, такой указатель отсутствует, поэтому информация о типе не существует.
просто расширяя ответ @Josh Einstein.
Ниже приведены два метода расширения, чтобы получить тип переменной, даже если он в настоящее время установлен в null.
/// <summary> /// Gets an object's type even if it is null. /// </summary> /// <typeparam name="T">The type of the object.</typeparam> /// <param name="that">The object being extended.</param> /// <returns>The objects type.</returns> public static Type GetTheType<T>(this T that) { return typeof(T); } /// <summary> /// Gets an object's type even if it is null. /// </summary> /// <param name="that">The object being extended.</param> /// <returns>The objects type.</returns> public static Type GetTheType(this object that) { if (that != null) { return that.GetType(); } return null; }
кроме того, вот два простых модульных теста для проверки методов расширения.
/// <summary> /// Tests to make sure that the correct type is return. /// </summary> [Test(Description = "Tests to make sure that the correct type is return.")] public void Test_GetTheType() { var value = string.Empty; var theType = value.GetTheType(); Assert.That(theType, Is.SameAs(typeof(string))); } /// <summary> /// Tests to make sure that the correct type is returned even if the value is null. /// </summary> [Test(Description = "Tests to make sure that the correct type is returned even if the value is null.")] public void Test_GetTheType_ReturnsTypeEvenIfValueIsNull() { string value = null; var theType = value.GetTheType(); Assert.That(theType, Is.SameAs(typeof(string))); }
Edit Извините, я забыл упомянуть, что мне нужна эта же функция для проекта, в котором я сейчас работаю. Все кредиты по-прежнему должны идти на @Josh Einstein: D
очень неприятно, что C# не позволяет сделать такое определение. И это не сродни вопросу о том, какой торт у вас был бы в пустой коробке - объект состоит из двух независимых компонентов - "воплощения" объекта и информации о классе, который был использован для создания объекта. Тот факт, что эта информация не может быть легко доступна, является ommission со стороны разработчиков C#.
все, что вы можете сделать в качестве определения, это скорее калечащий метод:
void Method(object obj) { if(obj is int) { //obj is of the int type } else if(obj is SomeComplexType) { //obj is of the SomeComplexType type } }
таким образом, вы можете видеть, что даже если объект равен нулю, его тип информации, тем не менее, путешествует вместе с объектом, он не теряется, вы просто не можете легко получить к нему доступ. Но это, мягко говоря, неудобно.
Если у вас есть объект сам по себе (скажем, в качестве входного параметра для метода с типом object), без определения или универсального типа, нет способа найти тип. Причина проста, вы не можете отправить сообщение (вызвать любой метод на) объект, чтобы спросить о типе.
могут быть и другие обходные пути, как вы видите в некоторых ответах, например, использование универсальных типов. В этом случае вы не спрашиваете нулевой объект, вы спрашиваете универсальный тип для его тип.
рассмотрим этот код:
public class MyClass1{} public class MyClass2{} public static void Test1() { MyClass1 one = null; MyClass2 two = (MyClass2) (object) one; one = new MyClass1(); //invalid cast exception two = (MyClass2)(object) one; }
тип выполнения нулевого экземпляра -
object
, по крайней мере с точки зрения безопасности типа.