提问人: 提问时间:6/17/2017 更新时间:6/23/2017 访问量:197
C#:使用不安全代码将变量与 default(T) 进行比较
C#: Use unsafe code to compare a variable to default(T)
问:
我想测试未知类型的变量是否已被同化为非值。default
该变量可能是结构类型,因此我无法用 .where T : class
结构的实现通常会假设其字段已经分配给,因此我不能使用 ,否则它将崩溃并出现空指针异常。IEquatable<T>
EqualityComparer<T>.default
(是的,我小心翼翼地确保结构的 0 值永远不会被视为有效值,因此我确信我可以专门处理它。
我愿意打开来实现这一点。我希望能够将正文写入此函数:/unsafe
unsafe static bool UnsafeIsDefault<T>(T a) {
// Error: Operator '==' cannot be applied to operands of type 'T' and 'T'
// return a == default(T);
// Real body goes here
}
我意识到另一种解决方案是限制 ,并为我打算在此处使用的每种类型编写一个实现,但我希望避免这种情况。where T : ICheckForDefault
interface ICheckForDefault { bool IsDefault(); }
答:
0赞
Mert Akcakaya
6/18/2017
#1
这个假设一个变量(类或结构)是 default(T) 或刚刚初始化且未更改字段/属性的变量(类或结构)是默认的。
class Program
{
static void Main(string[] args)
{
var defaultStruct = default(MyStruct);
PrintIsDefault(IsDefault(defaultStruct), nameof(defaultStruct));
var defaultInitializedStruct = new MyStruct();
PrintIsDefault(IsDefault(defaultInitializedStruct), nameof(defaultInitializedStruct));
var nonDefaultStruct = new MyStruct { Field1 = 13 };
PrintIsDefault(IsDefault(nonDefaultStruct), nameof(nonDefaultStruct));
var defaultChar = default(char);
PrintIsDefault(IsDefault(defaultChar), nameof(defaultChar));
var nonDefaultChar = 'a';
PrintIsDefault(IsDefault(nonDefaultChar), nameof(nonDefaultChar));
var defaultObject = default(object);
PrintIsDefault(IsDefault(defaultObject), nameof(defaultObject));
var nonDefaultObject = "string";
PrintIsDefault(IsDefault(nonDefaultObject), nameof(nonDefaultObject));
var defaultClass = default(MyClass);
PrintIsDefault(IsDefault(defaultClass), nameof(defaultClass));
var defaultInitializedClass = default(MyClass);
PrintIsDefault(IsDefault(defaultInitializedClass), nameof(defaultInitializedClass));
var nonDefaultClass = new MyClass { Field1 = 1, Prop1 = 2 };
PrintIsDefault(IsDefault(nonDefaultClass), nameof(nonDefaultClass));
Console.ReadLine();
}
private static bool IsDefault<T>(T value)
{
var typeInfo = typeof(T).GetTypeInfo();
if (typeInfo.IsClass)
{
if (typeInfo.IsPrimitive || value is string || value is object)
{
return Equals(value, default(T));
}
else
{
return Equals(value, default(T)) ? true : AreMembersDefault(value);
}
}
else
{
return typeInfo.IsPrimitive ? Equals(value, default(T)) : AreMembersDefault(value);
}
}
private static bool AreMembersDefault<T>(T value)
{
var fields = value.GetType().GetFields();
foreach (var field in fields)
{
if (!IsDefault((dynamic)(field.GetValue(value))))
{
return false;
}
}
var properties = value.GetType().GetProperties();
foreach (var prop in properties)
{
if (!IsDefault((dynamic)(prop.GetValue(value))))
{
return false;
}
}
return true;
}
private static void PrintIsDefault(bool isDefault, string varName)
{
Console.WriteLine($"{varName} is default: {isDefault}");
}
}
输出:
defaultStruct is default: True
defaultInitializedStruct is default: True
nonDefaultStruct is default: False
defaultChar is default: True
nonDefaultChar is default: False
defaultObject is default: True
nonDefaultObject is default: False
defaultClass is default: True
defaultInitializedClass is default: True
nonDefaultClass is default: False
0赞
user6629955
6/23/2017
#2
还有一种不同类型的比较更合适,称为 .Equals
请尝试以下代码:
System.Runtime.CompilerServices.RuntimeHelpers.Equals(value, default(T))
下一个:如何在.NET中进行引用比较?
评论
object.Equals(value, default(T))
IEquatable<T>
myStruct.Equals(default(T));
default(T)
不一定是结构体的安全值,因此调用其实现将崩溃。我真的只想在这里进行位比较,并在其他地方进行逻辑比较。Equals
object.Equals
Equals