我刚刚修改了深度C#的第4章,它处理了可空类型,我正在添加一个关于使用"as"运算符的部分,它允许你编写:
object o = ...;
int? x = o as int?;
if (x.HasValue)
{
... // Use x.Value in here
}
Run Code Online (Sandbox Code Playgroud)
我认为这非常简洁,它可以提高性能而不是C#1等效,使用"is"后跟一个演员 - 毕竟,这样我们只需要请求动态类型检查一次,然后进行简单的值检查.
然而,情况似乎并非如此.我在下面包含了一个示例测试应用程序,它基本上对对象数组中的所有整数求和 - 但该数组包含许多空引用和字符串引用以及盒装整数.该基准测试您必须在C#1中使用的代码,使用"as"运算符的代码,以及用于踢LINQ解决方案的代码.令我惊讶的是,在这种情况下,C#1代码的速度提高了20倍 - 即使是LINQ代码(考虑到所涉及的迭代器,我预计它会更慢)也胜过"as"代码.
可以isinst为空的类型的.NET实现真的很慢吗?是unbox.any导致问题的附加因素吗?还有另一种解释吗?目前,我觉得我必须在性能敏感的情况下包含警告,禁止使用它...
结果:
演员:10000000:121
As:10000000:2211
LINQ:10000000:2143
码:
using System;
using System.Diagnostics;
using System.Linq;
class Test
{
const int Size = 30000000;
static void Main()
{
object[] values = new object[Size];
for (int i = 0; i < Size - 2; i += 3)
{
values[i] = null;
values[i+1] …Run Code Online (Sandbox Code Playgroud) 我的比较结果false符合预期
bool eq = typeof(int?).Equals(typeof(int));
Run Code Online (Sandbox Code Playgroud)
现在我有这个代码
List<object> items = new List<object>() { (int?)123 };
int result = items.OfType<int>().FirstOrDefault();
Run Code Online (Sandbox Code Playgroud)
但这会返回123-无论如何该值是类型int?
怎么会这样?
编辑:底部的评论.还有,这个.
这就是让我感到困惑的一点.我的理解是,如果我有这样的枚举......
enum Animal
{
Dog,
Cat
}
Run Code Online (Sandbox Code Playgroud)
...我基本上完成的是定义了一个用两个定义的值调用的值类型Animal,Dog和Cat.这种类型派生自引用类型 System.Enum(值类型通常不能执行的操作 - 至少不在C#中 - 但在这种情况下是允许的),并且具有用于在int值之间来回转换的工具.
如果我刚刚描述上面的枚举类型的方式是真的,那么我希望以下代码抛出InvalidCastException:
public class Program
{
public static void Main(string[] args)
{
// Box it.
object animal = Animal.Dog;
// Unbox it. How are these both successful?
int i = (int)animal;
Enum e = (Enum)animal;
// Prints "0".
Console.WriteLine(i);
// Prints "Dog".
Console.WriteLine(e);
}
}
Run Code Online (Sandbox Code Playgroud)
通常,您不能将值类型System.Object从其确切类型以外的任何其他方式取消装箱.那以上怎么可能呢?这是因为如果该 …
class C<T> where T : struct {
bool M1(object o) => o is T;
bool M2(object o) => o is T?;
}
Run Code Online (Sandbox Code Playgroud)
传递null引用或盒装T值时,上述两种方法似乎表现相同.但是,生成的MSIL代码有点不同:
.method private hidebysig instance bool M1(object o) cil managed {
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst !T
IL_0006: ldnull
IL_0007: cgt.un
IL_0009: ret
}
Run Code Online (Sandbox Code Playgroud)
VS
.method private hidebysig instance bool M2(object o) cil managed {
.maxstack 8
IL_0000: ldarg.1
IL_0001: isinst valuetype [mscorlib]System.Nullable`1<!T>
IL_0006: ldnull
IL_0007: cgt.un
IL_0009: ret
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,o is …
如果我有一个Type,是否有一些简单的方法来告诉它使用Reflection代表一个可以为空的值类型?理想情况下,比以下更清洁(也更正确):
static bool IsNullable(Type type)
{
return type.IsValueType && type.Name.StartsWith("Nullable");
}
Run Code Online (Sandbox Code Playgroud) 为什么null隐式转换为System.Nullable<T>这样:
int? val = null;
Run Code Online (Sandbox Code Playgroud)
但是自定义Nullable<T>(从.net引用源修改)无法分配null,是否有一些编译魔术?谁能告诉我更多的内部暗示?
[Serializable]
public struct Nullable<T> where T : struct
{
private bool hasValue;
internal T value;
public Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
public bool HasValue
{
get
{
return hasValue;
}
}
public T Value
{
get
{
if (!HasValue)
{
throw new Exception();
}
return value;
}
}
public T GetValueOrDefault()
{
return value;
}
public T GetValueOrDefault(T defaultValue)
{
return …Run Code Online (Sandbox Code Playgroud) 每当我对 Nullable\xc2\xa0property 调用 PropertyInfo.GetValue 时,我都会获取可为 null 的结构的实际值,而不是结构本身。为什么?它是嵌入到语言中并且仅适用于 Nullable 类型还是自定义类可以与其他类型具有相同的功能。
\nc# ×5
.net ×3
nullable ×3
clr ×2
unboxing ×2
boxing ×1
casting ×1
cil ×1
enums ×1
inheritance ×1
performance ×1
reflection ×1
types ×1