Determining whether the default value has a default value without Equals; aka ReferenceEquals for structures

For some general helper methods that I write, I would like to be able to call special processing when this value is the default value for my type. For reference types, this is easy - the default value is null . I cannot use a type parameter, although I could get around this.

I can do something like this:

 public bool DetectPossiblyUninitializedValue(object val) { return val== null || val.GetType().IsValueType && Equals(val, Activator.CreateInstance(val.GetType()); } 

This is what I'm using right now, but it depends on the implementation of Equals . It is beautiful, but not perfect. In particular, some implementations may override Equals to support more convenient semantics in common scenarios. Actually, it’s not uncommon to view the default value as special here, because it is inevitable in .NET due to default initialization.

However, in this case, I just want to know if the object was initialized, and therefore I do not want any user equality or anything else. Basically, I want to know if the memory area occupied by the structure is filled, zero as supporters of the virtual machine after initialization, and nothing more. In a sense, I'm looking for something similar to ReferenceEquals for structs: a comparison not related to the native implementation of the main object.

How to compare the original structure values ​​without using Equals ? Can I compare the initial values ​​of the structure in general?

Edit: I use this to connect classes + structures representing domain-specific concepts related essentially by arbitrary code representing various business rules for a graphical interface. Some old code essentially deals with possibly nested string dictionaries for arbitrary objects, which requires a bunch of untested throws or dynamic ; creating them are prone to errors. Therefore, it is nice to work with typed objects relatively directly. On the other hand, it is useful for the GUI and packaging code to handle possibly uninitialized values ​​differently; and although in each case a type-by-type solution is possible, this is a lot of code; A reasonable default is helpful. In fact, I want the method to automatically generate a type identical to the other, but with all the properties / public fields extended to include the value “uninitialized”, but this is not a realistic function that can be expected - on the contrary, in a dynamic world this would be trivial achievable, although without any types elsewhere ...

Answers: Mehrdad sent a response to how to directly access structure bits ; I added an implementation using this to detect possibly uninitialized values .

+6
source share
7 answers

If you are worried about the overhead of boxing (and you are measured to be a bottleneck), you can solve it differently:

Create two temporary boxed instances of your structure as an object that can be reused for all structures. Using Reflection.Emit , create a method that uses the Unbox to copy the structure to the boxed version. (This avoids highlighting). Do the same with another struct box, and then call Equals on the objects.


Note:

I don't know if the overhead of calling a delegate is really faster, but you can still try and see. If you don’t recognize this, you can always make several comparisons at once - pass an array or something like that. It gets complicated, but if you know this is a bottleneck, then it may be worth it, depending on how large your struct .


Hackier Solution:

I do not support this decision, simply suggesting that it exist. If you do not know what this does, do not use it.

 bool UnsafeHackyEquals<T>(ref T a, ref T b) where T : struct { TypedReference pA = __makeref(a), pB = __makeref(b); var size = SizeOf<T>(); IntPtr* ppA = (IntPtr*)&pA, ppB = (IntPtr*)&pB; //Now ppA[0] is a pointer to a, and ppB[0] is a pointer to b. //You have the size of both, so you can do a bitwise comparison. } 

To find the size of the structure:

 static class ArrayOfTwoElements<T> { static readonly T[] Value = new T[2]; } static uint SizeOf<T>() { unsafe { TypedReference elem1 = __makeref(ArrayOfTwoElements<T>.Value[0] ), elem2 = __makeref(ArrayOfTwoElements<T>.Value[1] ); unsafe { return (uint)((byte*)*(IntPtr*)(&elem2) - (byte*)*(IntPtr*)(&elem1)); } } } 

Yes, that would be undocumented. But if you are worried about this, you can simply emit this method (because the operation code of MkRefAny really documented), so this is not a problem. However, this example may break on other platforms, so be careful ...

+4
source

With limited time, I have to understand your requirements, I'm just going to quit something for you to think about. although this is due to operator overloading (which, in turn, is implementation-specific):

 public struct Foo { public int Bar; public static bool operator ==(Foo a, Foo b) { return a.Bar == b.Bar; } public static bool operator !=(Foo a, Foo b) { return !(a.Bar == b.Bar); } public override bool Equals(object obj) { return base.Equals(obj); } } 

Then for comparison:

 Foo foo1 = new Foo(); Foo foo2 = new Foo { Bar = 1 }; if (foo1 == default(Foo)) { Console.WriteLine("foo1 is equal to default"); } if (foo2 != default(Foo)) { Console.WriteLine("foo2 is not equal to default"); } 
+2
source

The original poster is here: I decided ... not ... using the solution below, extended from Mehrdad's notes. It works, but I don't think the general trick is to catch a few more uninitialized values ​​in the default implementation.

But if others ever care about it, this is:

 public static bool PossiblyUninitialized(object a) { if(a == null) return true; Type t = a.GetType(); return t.IsValueType && helpers.GetOrAdd(t, _=>{ var method = typeof(StructHelpers<>).MakeGenericType(t) .GetMethod("PossiblyUninitialized"); var objParam = Expression.Parameter(typeof(object),"obj"); return Expression.Lambda<Func<object,bool>>( Expression.Call(method,Expression.Convert(objParam,t)), objParam ).Compile(); })(a); } static ConcurrentDictionary<Type, Func<object,bool>> helpers = new ConcurrentDictionary<Type, Func<object,bool>>(); unsafe static class StructHelpers<T> where T : struct { public static readonly uint ByteCount = SizeOf(); static uint SizeOf() { T[] arr = new T[2]; var handle = GCHandle.Alloc(arr); TypedReference elem0 = __makeref(arr[0]), elem1 = __makeref(arr[1]); return (uint)((byte*)*(IntPtr*)(&elem1) - (byte*)*(IntPtr*)(&elem0)); handle.Free(); } public static bool PossiblyUninitialized(T a) { TypedReference pA = __makeref(a); var size = ByteCount; IntPtr* ppA = (IntPtr*)(&pA); int offset = 0; while(size - offset>=8) { if(*(long*)(*ppA+offset) != 0) return false; offset+=8; } while(size - offset>0) { if(*(byte*)(*ppA+offset) != 0) return false; offset++; } return true; } } void Main()//LINQpad { StructHelpers<decimal>.ByteCount.Dump(); PossiblyUninitialized(0m).Dump();//true PossiblyUninitialized(0.0m).Dump();//false PossiblyUninitialized(0.0).Dump();//true PossiblyUninitialized(-0.0).Dump();//false PossiblyUninitialized("").Dump();//false } 
+1
source

Comparison of general purpose structures should be done using something like Reflection - basically you need to compare each field in the structures separately. You can use unsafe / unmanaged code, for example, to copy a structure to bytes [] and scan non-zero bytes, but rely on VM's basic guarantees, as this might be a bad idea. (C #, the language, only ensures that each field has its own default value — the fact that the default value is 0 is a CLR-specific part that can change.)

There are several solutions for comparing structures, including the rather compact LINQ solution, in answers to Comparing two structs values ​​in C # .

You can use the default keyword to get a default structure that can be compared with, for example:

  var blank = default(type) 

Based on this LINQ solution, this should do what you want:

 static bool IsDefault<T> ( T b ) where T : struct { T a = default(T); var differences = from fielda in a.GetType().GetFields() join fieldb in b.GetType().GetFields() on fielda.Name equals fieldb.Name where !fielda.GetValue(a).Equals(fieldb.GetValue(b)) select fielda.Name; return !differences.Any(); } 

EDIT:

If your structures, in turn, have their own members, which are structures, this will unfortunately return to .Equals() to compare them. If this problem will work with a longer foreach on fields and processing fields of type struct separately, then by the same principle.

0
source

If the Value Types you are considering is all “under your control” or will be configured to work with your code, you can always force them to implement the readonly bool IsInitialized and check it using reflection.

If not, it's hard for me to do what you want without using Equals . Theoretically, you can iterate over fields using reflection to check if all fields are set by default.

0
source

Is it possible to compare the initial values ​​of the structure? - Nope . The CLR itself uses reflection to compare two structures for each field. Equal is your only hope. Value types must implement Equals, which are no different from matching fields by field. Otherwise, the Value Type is not a ValueType.

Consider the following

 struct Bla { int Data; } ... { Bla a = new Bla(); Bla b = new Bla(); a.Data = 10; a.Data = 0; Console.Writeline(IsDefault(a)); Console.Writeline(IsDefault(b)); } 

What do you expect to receive? We are talking about structures here.

0
source

Eamon Nerbonne's answer can now be implemented using System.Runtime.CompilerServices.Unsafe without using undocumented / unsupported functions and raw pointers:

 // Essentially unchanged from Eamon Nerbonne version public static bool IsDefaultValue([CanBeNull] object a) { if (a == null) return true; Type type = a.GetType(); return type.IsValueType && helpers.GetOrAdd( type, t => { var method = typeof(StructHelpers<>).MakeGenericType(t) .GetMethod(nameof(StructHelpers<int>.IsDefaultValue)); var objParam = Expression.Parameter(typeof(object), "obj"); return Expression.Lambda<Func<object, bool>>( Expression.Call(method, Expression.Convert(objParam, t)), objParam) .Compile(); })(a); } static readonly ConcurrentDictionary<Type, Func<object,bool>> helpers = new ConcurrentDictionary<Type, Func<object,bool>>(); static class StructHelpers<T> where T : struct { // ReSharper disable StaticMemberInGenericType static readonly int ByteCount = Unsafe.SizeOf<T>(); static readonly int LongCount = ByteCount / 8; static readonly int ByteRemainder = ByteCount % 8; // ReSharper restore StaticMemberInGenericType public static bool IsDefaultValue(T a) { if (LongCount > 0) { ref long p = ref Unsafe.As<T, long>(ref a); // Inclusive end - don't know if it would be safe to have a ref pointing // beyond the value as long as we don't read it ref long end = ref Unsafe.Add(ref p, LongCount - 1); do { if (p != 0) return false; p = ref Unsafe.Add(ref p, 1); } while (!Unsafe.IsAddressGreaterThan(ref p, ref end)); } if (ByteRemainder > 0) { ref byte p = ref Unsafe.Add( ref Unsafe.As<T, byte>(ref a), ByteCount - ByteRemainder); ref byte end = ref Unsafe.Add(ref p, ByteRemainder - 1); do { if (p != 0) return false; p = ref Unsafe.Add(ref p, 1); } while (!Unsafe.IsAddressGreaterThan(ref p, ref end)); } return true; } } 
0
source

All Articles