-
Notifications
You must be signed in to change notification settings - Fork 4.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Marshal.SizeOf(Type) is throwing incorrectly on generic types #46426
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
@pgrawehr This is the expected behavior. This behavior is consistent with .NET Framework and has been this way for quite some time - please let me know if I am missing the scenario. The fact that a Generic type has a closed type or not isn't a consideration for this API. Relaxing this to permit closed Generic types is possible, but it would require a discussion. At this point I believe the open question is, is this a reported bug in the documentation or is the request to permit this operation? |
It should be noted that the |
I believe we had previously discussed updating |
I might be remembering #32963 (comment), which was related to |
@AaronRobinsonMSFT I know that it's probably a rare scenario that one uses a struct with a generic parameter for blitting, however I see no reason why this shouldn't work (at least if the generic parameter is by itself blittable). Do note that it works as I would expect with the other overloads of SizeOf(), i.e. given an actual instance of the generic type. The |
Yes and I think that is the point actually. I've given this some more thought and rummaged through some interop code bases and I think this API is commonly used for the "is blittable" check for a Here are some other related issues to Generics and the |
@AaronRobinsonMSFT That's what I'm expecting. I'm expecting Sizeof(Type) to work when Type is blittable. And a generic struct with (defined) generic arguments is blittable. Consider (from the example above): [StructLayout(LayoutKind.Sequenzial, Pack=1)]
private struct GenericStruct<T>
{
public T _data1;
public int _data2;
} then the type Note that all I'm suggesting is that the condition if (t.IsGenericType)
{
throw new ArgumentException(SR.Argument_NeedNonGenericType, nameof(t));
} be changed to
This would also be in line with the documentation, where it says that Conceptually, the entire test could be left away as well, since the implementation further down would throw anyway on something that is not blittable (only maybe with a less clear message). |
Agreed, but it isn't in .NET Framework and that means assumptions are baked into applications for that reason. Changing this would impact those assumptions about how code has evolved and branches. |
Code that used to work would still work. I'm actually not expecting anyone to use this method to test whether an object contains generics, as this can be tested directly, not using this method and relying on catching the exception. No code should ever catch ArgumentException. Also, if I understand #43486 and #103 correctly, marshalling generics was not at all supported in .NET Framework. |
That is precisely my point. Consider the following for code that was initially ported from .NET Framework in the .NET Core 1.0 timeframe. bool CanUseType(Type t)
{
try
{
Marshal.SizeOf(t);
return true;
}
catch
{
return false;
}
} Whatever logic this was blocking included cases when I referenced the other issues precisely to ensure or at least attempt to verify older code that was ported would continue to work. Opening up this one API could yield failures further down because other APIs haven't been updated. However, if we update how we think about Generics in all these situations then changing this behavior makes perfect sense. All I am getting at here is a piecewise permissiveness isn't something the interop team is generally comfortable with because it can expose existing fragile code paths to break in unexpected and dangerous ways. |
I see your point, and digging a bit further, the problem seems to be larger than what I anticipated. It appears that when generic types where made blittable for .NET core, it was only partially done. I started with being confused that I guess we need a bunch of test cases first to test what works and what doesn't. And probably first a decision what behavior we would like to have and whether we risk taking a possibly breaking change. And then fix the code or update the documentation. The fact that the documentation states what I was expecting is an indication that it was at least planned to do the change at some point. |
When generic interop types were made possible, it was really just relaxing the restriction in the interop logic so it could cross the managed/native boundary. There wasn't also work done to update Put another way, these types must already be blittable and so you don't want to use any of the This is all "inline" with an effort to move users off of the built-in marshalling support and onto things like |
I see, but then I would expect remarks in the documentation of the Marshal class that it is considered legacy and which alternatives should be used. Instead, we have documentation that suggests that |
Whats the state of this issue? |
As indicated above, generic types must already be blittable to cross the P/Invoke boundary and so |
However it does not support common Types, correct? Would be nice to see a Type based API that is capable of determining those sizes. |
Description
Marshal.SizeOf(typeof(somegenericstruct))
throwsArgumentException
when T is a closed generic type. It should only throw on open generic types.Here's the implementation
Configuration
Seen on .NET 5.0
Analysis
The documentation says that
ArgumentException
is thrown if t is a generic type definition. The implementation however throws when it is any generic type (including a closed one). The implementation of the similar methoddoes not throw this exception - it can be used as workaround.
Here's some test code:
The text was updated successfully, but these errors were encountered: