C#:使用不安全代码将变量与默认值(T)进行比较
我想测试未知类型的变量是否被分配为非默认值 这个变量可能是一个结构类型,所以我不能用C#:使用不安全代码将变量与默认值(T)进行比较,c#,.net,equality,unsafe,iequalitycomparer,C#,.net,Equality,Unsafe,Iequalitycomparer,我想测试未知类型的变量是否被分配为非默认值 这个变量可能是一个结构类型,所以我不能用解决这个问题,其中t:class 结构的IEquatable实现通常会假定其字段已分配给,因此我不能使用EqualityComparer.default,否则它将因空指针异常而崩溃 (是的,我正在小心地确保结构的0值永远不会被视为有效值,因此我确信我可以特别对待它。) 我愿意打开/unsafe来完成这项任务。我希望能够将正文写入此函数: unsafe static bool UnsafeIsDefault<
解决这个问题,其中t:class
结构的IEquatable
实现通常会假定其字段已分配给,因此我不能使用EqualityComparer.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
}
不安全静态bool UnsafeIsDefault(TA){
//错误:运算符“==”不能应用于“T”和“T”类型的操作数
//返回a==默认值(T);
//这里有真人
}
我意识到另一种解决方案是使用接口ICheckForDefault{bool IsDefault();}约束
其中的T:ICheckForDefault
,并为我打算在这里使用的每种类型编写一个实现,但我希望避免这种情况。这一方案假设一个变量(类或结构)是默认值(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}");
}
}
这一个假设一个变量(类或结构)是默认的(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}");
}
}
有一种不同类型的比较更合适,称为
Equals
请尝试以下代码:
System.Runtime.CompilerServices.RuntimeHelpers.Equals(value, default(T))
有一种不同类型的比较更合适,称为
Equals
请尝试以下代码:
System.Runtime.CompilerServices.RuntimeHelpers.Equals(value, default(T))
object.Equals(value,default(T))
有什么问题吗?使用IEquatable
可以执行myStruct.Equals(default(T))
其中T是结构的类型默认值(T)
不一定是结构的安全值,因此调用其Equals
实现将崩溃。我真的只想在这里进行位比较,在其他地方进行逻辑比较。您可以按照上面的建议使用object.Equals(value,default(T))。它不会调用struct Equals方法,即使您重写了该方法或实现了IEquatable。因此,即使您有一些结构在其相等比较中不需要默认字段值,它也不会崩溃。@Evk I测试了它,并且object.Equals
似乎正在调用重写的Equals
。还说“这意味着如果objA重写Object.Equals(Object)方法,则调用该重写。”@PetSerAI,这很有效!如果你提交的话,我会接受你的回答。但是它是否是框结构呢?object.Equals(value,default(T))
?使用IEquatable
可以执行myStruct.Equals(default(T))
其中T是结构的类型默认值(T)
不一定是结构的安全值,因此调用其Equals
实现将崩溃。我真的只想在这里进行位比较,在其他地方进行逻辑比较。您可以按照上面的建议使用object.Equals(value,default(T))。它不会调用struct Equals方法,即使您重写了该方法或实现了IEquatable。因此,即使您有一些结构在其相等比较中不需要默认字段值,它也不会崩溃。@Evk I测试了它,并且object.Equals
似乎正在调用重写的Equals
。还说“这意味着如果objA重写Object.Equals(Object)方法,则调用该重写。”@PetSerAI,这很有效!如果你提交的话,我会接受你的回答。但它是否是一个盒子结构?