C# 检查对象是否为值类型的最有效方法
警告:此代码糟透了,请参见ANTHONY的评论 哪个更快 一,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.另一件事我的第一个答案是写一个简单的测试,然后自己找
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)
对于nulledNullable
来说似乎有问题。我不是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!
{
//...
}