Наиболее эффективный способ проверить, является ли объект типом значения
ПРЕДУПРЕЖДЕНИЕ: НАСТОЯЩИЕ УКАЗАНИЯ КОДА, ПОСМОТРЕТЬ ЭНТОННЫЕ КОММЕНТАРИИ
Что быстрее?
1.
public bool IsValueType<T>(T obj){
return obj is ValueType;
}
2.
public bool IsValueType<T>(T obj){
return obj == null ? false : obj.GetType().IsValueType;
}
3.
public bool IsValueType<T>(T obj){
return default(T) != null;
}
4.Что-то еще
Ответы
Ответ 1
Вы действительно не тестируете объект - вы хотите проверить тип. Чтобы вызвать их, вызывающий должен знать тип, но... meh. Учитывая подпись <T>(T obj)
, единственным разумным ответом является:
public bool IsValueType<T>() {
return typeof(T).IsValueType;
}
или если мы хотим использовать пример объекта для целей вывода типа:
public bool IsValueType<T>(T obj) {
return typeof(T).IsValueType;
}
для этого не требуется бокс (GetType()
- бокс) и не имеет проблем с Nullable<T>
. Более интересным является случай, когда вы проходите object
...
public bool IsValueType(object obj);
здесь у нас уже есть серьезные проблемы с null
, так как это может быть пустая Nullable<T>
(a struct) или класс. Но разумная попытка:
public bool IsValueType(object obj) {
return obj != null && obj.GetType().IsValueType;
}
но обратите внимание, что он неправильный (и нефиксируемый) для пустых Nullable<T>
s. Здесь становится бессмысленным беспокоиться о боксе, поскольку мы уже в коробке.
Ответ 2
Мой первый ответ - написать простой тест и узнать сами.
Мой второй ответ (без какого-либо тестирования с моей стороны, конечно) был бы опцией 1. Это простейшая проверка. Второй метод включает в себя два отдельных проверки, в то время как третий включает создание экземпляра по умолчанию для типа.
Вы также должны учитывать читаемость. Структура уже дает вам возможность иметь следующее в вашем коде:
if(someObj is ValueType)
{
// Do some work
}
Почему бы даже не создать метод, который просто превратил бы указанный выше оператор (предполагая, что вы сделали свой статический метод и позволили компилятору вывести общий тип):
if(IsValueType(someObj))
{
// Do some work
}
Ответ 3
Определение структуры на самом деле определяет два типа: тип значения и тип класса, который происходит от System.ValueType
. Если создается запрос на создание переменной, параметра, поля или массива (в совокупности "место хранения" ) типа, который происходит из System.ValueType, система вместо этого создаст место хранения, в котором будут храниться поля объекта, а не сохраняя ссылку на объект, в котором появляются эти поля. С другой стороны, если создается запрос на создание экземпляра типа, полученного из System.ValueType, система создаст экземпляр объекта класса, который происходит из System.ValueType.
Это можно продемонстрировать, создав структуру, которая реализует IValue:
interface IValue {int value {get; set;}};
struct ValueStruct : IValue
{
public int value {get; set;}};
}
с общей тестовой программой и кодом для ее переноса:
static void Test<T>(T it) where T:IValue
{
T duplicate = it;
it.value += 1;
duplicate.value += 10;
Console.WriteLine(it.value.ToString());
}
static void Test()
{
ValueStruct v1 = new ValueStruct();
v1.value = 9;
IValue v2 = v1;
Test<ValueStruct>(v1);
Test<ValueStruct>(v1);
Test<IValue>(v1);
Test<IValue>(v1);
Test<IValue>(v2);
Test<IValue>(v2);
}
Обратите внимание, что в каждом случае вызов GetType по параметру, переданному Test, приведет к ValueStruct, который будет сообщать себя как тип значения. Тем не менее, переданный элемент будет только "реальным" типом значения при первых двух вызовах. На третьем и четвертом вызовах это будет действительно тип класса, о чем свидетельствует тот факт, что изменение на duplicate
повлияет на it
. И на пятом и шестом вызовах это изменение будет передано обратно на v2, поэтому второй вызов будет "видеть" его.
Ответ 4
static class Metadata<T>
{
static public readonly Type Type = typeof(T);
static public readonly bool IsValueType = Metadata<T>.Type.IsValueType;
}
//fast test if T is ValueType
if(Metadata<T>.IsValueType) //only read static readonly field!
{
//...
}
Ответ 5
Существует два правила:
1-Все классы - это ссылочные типы, такие как Object и String, поэтому они поддерживаются .NET Framework classes.
Структуры 2-All - это значение, такие как bool и char, хотя он содержит ссылочный элемент, поэтому он поддерживается .NET Framework структуры.. p >
Просто щелкните правой кнопкой мыши по любому типу и Перейти к определению, если это класс, поэтому он означает ссылочный тип else, если он является Struct, поэтому он означает тип значения:)