[Proposal] Add sizeof(T) support for unmanaged constraint #8750
Replies: 19 comments
-
I think you will still have to use struct ValueStruct { bool b1,b2,b3,b4; }
Unsafe.SizeOf<ValueStruct>().Dump();
Marshal.SizeOf<ValueStruct>().Dump();
|
Beta Was this translation helpful? Give feedback.
-
@dangi12012 @omariom - If you are marshaling a struct then you must use the Marshal.SizeOf - that is what it's intended for. However I agree that being able to get the physical size in managed memory might be useful for some situations (I have done this before and wrote utility code to determine this at runtime). However @dangi12012 your post is unclear because sizeof(T) does actually compile and work...
|
Beta Was this translation helpful? Give feedback.
-
Thats right. I need the size of the struct inside Memory. I dont plan to marshal it for C++. With Span developers really get a powerful tool which can be used in a safe manner. sizeof(T) should work with unmanaged keyword because the struct size can be determined at compile time and is blittable (No reference Types).
|
Beta Was this translation helpful? Give feedback.
-
Really? That code can be compiled without any error. Do you want this to be compilable without unsafe context? |
Beta Was this translation helpful? Give feedback.
-
Yes. This should be compilable without the use of the unsafe context. Span works in a safe context, so sizeof(T) where T : unmanaged would speed up things AND is safe after all. |
Beta Was this translation helpful? Give feedback.
-
For arbitrary struct T, the size will only be known at runtime. For example, consider IntPtr fields, auto layout, and CLR implementation-defined padding. (Or did you mean JIT compile time?)
IMHO, it should work without unsafe context. It should even work without the unmanaged constraint. I have never understood why |
Beta Was this translation helpful? Give feedback.
-
Could we proceed with this and make |
Beta Was this translation helpful? Give feedback.
-
@xoofx, I would recommend creating an individual issue requesting the change. |
Beta Was this translation helpful? Give feedback.
-
@xoofx - An alternative is to write a method that dynamically generates a delegate from IL instructions. That IL delegate is an algorithm that creates an instance of T and then determines the difference between the instance's address and the address of its highest offset member field. It then adds the length of that field. This reliably determines the physical size of 'T' as its defined in the managed environment. By making this a static operation with some form of dictionary, the above is done once and thereafter the cached size (keyed on typeof(T)) is then instantly available with almost no overhead at runtime. I used this to great effect once. |
Beta Was this translation helpful? Give feedback.
-
Will do
Hm, sorry, I'm not sure to follow. We have already sizeof at the IL level, we can expose it and we are already using it in C#. We are just asking to make this sizeof operator fully available in C# so that we don't have to rely on an external IL lib to "un-restrict" it. The sizeof operator is important at IL level because it boils down to a compile time constant (at JIT or AOT time), so not sure why we would go to a more complicated route with allocations, a dictionary, locking...etc (note that you could make it without a dictionary actually with a static readonly field), just to get an information that is straightforward to get, even today, but alas, not integrated by default in the language, so we have to rely on an external/IL compiled lib (like |
Beta Was this translation helpful? Give feedback.
-
Well then implement it please. |
Beta Was this translation helpful? Give feedback.
-
It would be nice if these worked:
|
Beta Was this translation helpful? Give feedback.
-
@imxzjv, The first scenario can't work because The runtime will treat The latter can't work because fixed sized buffers are constrained to a limited set of primitive type and would require a new feature (such as the already championed proposal: #1314) to extend that to support any type and be useable in "safe" code (relying on the ref return fe as true to work and relying on explicitly declared structs for type layout and sizing to be correct). |
Beta Was this translation helpful? Give feedback.
-
2- would work with a new constraint: 1- works for static readonly but can never ever work for const. This compiles fine and static readonly is the same as const as far as the jit is concerned.
If my proposal were implemented you could drop the unsafe. Since the struct is safe you can see how my proposal makes sense for T : unmanaged |
Beta Was this translation helpful? Give feedback.
-
....and literally every single struct type made in all of .NET ever? Sure, it's illegal now, but having a |
Beta Was this translation helpful? Give feedback.
-
@tannergooding Here is an example of where I think |
Beta Was this translation helpful? Give feedback.
-
Related is the proposal championed at #1828, which was rejected:
|
Beta Was this translation helpful? Give feedback.
-
It would make my code nicer when passing An example from last week is https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerrawinputdevices where I need to pass |
Beta Was this translation helpful? Give feedback.
-
Here is a compelling use case, in my opinion. Spans have been introduced to, among other things, limit the need to use unsafe code in performance-critical scenarios. One case would be to allocate temporary memory on the stack rather than the heap. I.e. Span buffer = stackalloc int[..]; C# has also introduced features to allow better abstractions over math (and others) with static members on interfaces. This feature, along with the case of arbitrary custom types, makes it more likely to have generic methods working on unmanaged types. However, given a method with a generic type parameter constrained to unmanaged, it may be dangerous to allocate stack memory for it since the actual size of T is unknown. Allocating stack memory may be reasonable given a byte as T, but not if T is a large struct. Example (please disregard that this could be implemented more efficiently without this feature):
This will give you a compilation error (CS0233) because sizeof() is limited to an unsafe context. However, it seems it should be perfectly safe when T is constrained to unmanaged. Removing this limitation would allow this scenario to be handled without an unsafe context. |
Beta Was this translation helpful? Give feedback.
-
If I use the unmanaged constraint on a generic type parameter the underlying type cannot contain any reference type. Ergo the size is known.
Can we have support for this:
This would make Marshal and unsafe unnecessary for much Pinvoke Code. Which is a very good thing for speed.
Beta Was this translation helpful? Give feedback.
All reactions