-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
UnsafeAccessor
and structs with no parameterless constructor
#90038
Comments
Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices Issue Details
cc @jkotas Code: public static class Program
{
public static void Main()
{
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static S1 Constructor1();
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static S1 Constructor2(int i);
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static S2 Constructor3();
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static S2 Constructor4(int i);
Console.WriteLine(Constructor2(5).i);
Console.WriteLine(Constructor1().i);
Console.WriteLine(Constructor4(5).i);
Console.WriteLine(Constructor3().i);
}
}
public readonly struct S1
{
public readonly int i;
public S1() => this.i = 0;
public S1(int i) => this.i = i;
}
public readonly struct S2
{
public readonly int i;
public S2(int i) => this.i = i;
} Output:
|
Worth noting that public static class Program
{
public static unsafe void Main()
{
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
extern static S[] Constructor(int i);
Console.WriteLine(Constructor(5).Length);
}
}
public readonly struct S
{
public readonly int i;
public S(int i) => this.i = i;
} despite the ECMA saying |
This looks like intended behavior to me. This feature does not do any transformations that C# does with a method call (overload resolution, look for the method in the type hierarchy, substitute default arguments, decide whether it is call or callvirt, ....). It makes sense that it does not replace a
newobj should work fine for zero-based, one-dimensional arrays. The behavior of UnsafeAccessor matches behavior of newobj IL instruction for this case. It is wasteful to create zero-based one-dimensional arrays using newobj instruction. On the other hand, all arrays have runtime provided constructors that can be used with newobj instruction. It does not make sense to block one of the constructors just because there is more efficient alternative. We do not block less efficient constructs anywhere else. For example, We can add a spec augment to say "should be created" instead of "are created" here. |
I'm fine with such behaviour but I think it might be potentially confusing for some users and might lead to some serialization libraries having unexpected behaviour with structs since they'd expect it to behave the same as However in such case I think that having an intrinsic like: public class Type
{
public bool HasParameterlessConstructor { get; }
} would be useful to know whether a value type needs to use For context, the question about this behaviour stems from me wondering whether |
It is true, that this was intended, a constructor access always results in a
Is this worth special casing in a future release? If not, I think we should update the doc and close this issue. If so, I can do this in .NET 8 or .NET 9. |
@lambdageek @fanyang-mono as FYI |
Contributes to dotnet#90038
It is not clear whether we would want to allow
It may be worth special casing for the type visibility skipping if/once we implement that. There is no point in using
Agree. Submitted #90070 with the doc update. |
UnsafeAccessor
(from #81741) seems to currently throwMissingMethodException
when trying to construct a struct with no paramters when it doesn't contain a parameterless constructor.Since you can do so fine with
new()
in C# and withActivator.CreateInstance
, this got me wondering if this behaviour is intended, or if it should work fine.cc @jkotas
Code:
Output:
The text was updated successfully, but these errors were encountered: