C# 检查对象是否为值类型的最有效方法

C# 检查对象是否为值类型的最有效方法,c#,.net,performance,value-type,C#,.net,Performance,Value Type,警告:此代码糟透了,请参见ANTHONY的评论 哪个更快 一, public bool IsValueType(T obj){ 返回obj为ValueType; } 二, public bool IsValueType(T obj){ 返回obj==null?false:obj.GetType().IsValueType; } 三, public bool IsValueType(T obj){ 返回默认值(T)!=null; } 4.另一件事我的第一个答案是写一个简单的测试,然后自己找

警告:此代码糟透了,请参见ANTHONY的评论

哪个更快

一,

public bool IsValueType(T obj){
返回obj为ValueType;
}
二,

public bool IsValueType(T obj){
返回obj==null?false:obj.GetType().IsValueType;
} 
三,

public bool IsValueType(T obj){
返回默认值(T)!=null;
}

4.另一件事

我的第一个答案是写一个简单的测试,然后自己找出答案

我的第二个答案(当然,我没有做任何测试)是选项1。这是最简单的支票。第二种方法涉及两个单独的检查,而第三种方法涉及创建类型的默认实例

<>你也应该考虑可读性。该框架已使您能够在代码中包含以下内容:

if(someObj is ValueType)
{
    // Do some work
}
为什么还要费心创建一个简单地将上述语句转换为的方法(假设您将方法设置为静态并允许编译器推断泛型类型):


您并不是真正在测试一个对象,而是要测试该类型。要调用这些,调用方必须知道类型,但是。。。无聊的。给出一个签名(T obj)唯一明智的答案是:

public bool IsValueType<T>() {
    return typeof(T).IsValueType;
}
在这里,
null
已经存在大量问题,因为这可能是一个空的
null
(一个结构)或一个类。但合理的尝试是:

public bool IsValueType(object obj) {
    return obj != null && obj.GetType().IsValueType;
}

但是请注意,对于空的
Nullable
s,它是不正确的(并且是不可调整的)。在这里,担心装箱变得毫无意义,因为我们已经装箱了。

定义结构实际上定义了两种类型:值类型和派生自
System.ValueType
的类类型。如果请求创建从System.ValueType派生的类型的变量、参数、字段或数组(统称为“存储位置”),系统将创建一个存储位置,该存储位置将存储对象的字段,而不是存储对这些字段出现在其中的对象的引用。另一方面,如果请求创建从System.ValueType派生的类型的实例,系统将创建从System.ValueType派生的类的对象实例

这可以通过创建一个实现IValue的结构来证明:

interface IValue {int value {get; set;}}; struct ValueStruct : IValue { public int value {get; set;}}; } 接口IValue{int value{get;set;}; 结构值结构:IValue { 公共int值{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); } 静态孔隙试验(T it),其中T:IValue { T重复=它; it.value+=1; 重复值+=10; Console.WriteLine(it.value.ToString()); } 静态孔隙试验() { ValueStruct v1=新的ValueStruct(); v1.1值=9; IValue v2=v1; 试验(v1); 试验(v1); 试验(v1); 试验(v1); 试验(v2); 试验(v2); } 请注意,在任何情况下,对传递给Test的参数调用GetType都会生成ValueStruct,它将自己报告为值类型。尽管如此,传入的项在前两次调用中将仅为“实”值类型。在第三次和第四次调用中,它实际上是一种类类型,这一点可以通过更改
duplicate
将影响
it
这一事实来证明。在第五次和第六次调用中,更改将传播回v2,因此第二次调用将“看到”它。

有两条规则:

1-所有类都是引用类型,如对象和字符串,因此.NET Framework支持类

2-所有结构都是value类型,例如bool和char,尽管它包含引用成员,所以它受.NET Framework结构的支持

只需右键单击任何类型,然后转到定义如果它是类,则表示它是引用类型;如果它是结构,则表示它是值类型:)

静态类元数据
{
静态公共只读类型Type=typeof(T);
静态公共只读bool IsValueType=Metadata.Type.IsValueType;
}
//快速测试T是否为ValueType
if(Metadata.IsValueType)//仅读取静态只读字段!
{
//...
}

性能真的很重要吗?因为它确实是微观优化。编写的方法2和3无效<对于引用类型,code>obj==null | |将返回true<代码>默认值(T)!=null将为
可为null的
结构返回false。您对方法2的编辑仍将无效<代码>对象!=null | |对于非null引用类型的对象将返回true。因为我太挑剔了,呃,我的意思是有帮助,方法1不喜欢null
可null
对象<代码>整数?bar=null将其传递给函数,得到false。(老实说,没想到)方法2最新编辑<代码>返回obj==null?false:…仍然为
可为null的
提出了一个问题。谢谢-我并不主张创建一个测试它的方法。我这样写是为了清楚我问的问题
(someObj是ValueType)
对于nulled
Nullable
来说似乎有问题。我不是IL大师,但我相信这涉及到拳击,这在这个场景中不起作用。你怎么知道
是最简单的检查?例如,您可以测试一个对象是否实现了一个接口,这并不是那么“简单”。不知道编译器是如何处理它的,但请检查和(由它调用)是如何实现的。您是否知道更多,或者您只是认为
is
更快,因为它看起来更简单?是否有办法绕过
IsValueType
属性?我使用的是.NET DNX,它不支持此属性。
typeof(ValueType)。IsAssignableFrom(t)
也不起作用。@Shimmy--在OP的代码中--
if(default(t)!=null)
应该起作用。在DNX/.NET Core中,你可以像这样做
typeof(你的类型)。GetTypeInfo()。IsValueType
作为背景信息,但是什么呢
public bool IsValueType<T>() {
    return typeof(T).IsValueType;
}
public bool IsValueType<T>(T obj) {
    return typeof(T).IsValueType;
}
 public bool IsValueType(object obj);
public bool IsValueType(object obj) {
    return obj != null && obj.GetType().IsValueType;
}
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); }
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!
{
    //...
}