Skip to content
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

The ConstructorBuilder and MethodBuilder generated parameter should not has default value by default. #20909

Closed
edwardmeng opened this issue Apr 5, 2017 · 5 comments · Fixed by #84550
Labels
area-System.Reflection.Emit bug good first issue Issue should be easy to implement, good for first-time contributors help wanted [up-for-grabs] Good issue for external contributors
Milestone

Comments

@edwardmeng
Copy link

The HasDefaultValue of parameters should be false by default, for the constructors and methods generated from System.Reflection.Emit.ConstructorBuilder and System.Reflection.Emit.MethodBuilder. But actually the HasDefaultValue of the parameters are true. It means the emitter generates parameter default values as null unexpected. The sample code as following:

var builder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("DynamicProxyGenAssembly"), AssemblyBuilderAccess.Run).DefineDynamicModule("DynamicProxyGenAssembly");
var type = builder.DefineType("MyProxy", TypeAttributes.Public);

var constructorBuilder = type.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, new[] {typeof(Version)});
var il = constructorBuilder.GetILGenerator();
il.Emit(OpCodes.Ret);

var methodBuilder = type.DefineMethod("DoSomething", MethodAttributes.Public, CallingConventions.Standard, typeof(void),new[] {typeof(Version)});
il = methodBuilder.GetILGenerator();
il.Emit(OpCodes.Ret);

var typeInfo = type.CreateTypeInfo();
var constructor = typeInfo.GetConstructor(new[] {typeof(Version) });
var parameters = constructor.GetParameters();
Assert.False(parameters[0].HasDefaultValue);  // Fails

var method = typeInfo.GetMethod("DoSomething", new[] {typeof(Version)});
parameters = method.GetParameters();
Assert.False(parameters[0].HasDefaultValue); // Fails

But the DynamicMethod has the correct parameter default value as expected. The sample code as following:

var method = new DynamicMethod("x", typeof(void), new [] { typeof(Version) });
var il = method.GetILGenerator();
il.Emit(OpCodes.Ret);
var delegateMethod = method.CreateDelegate(typeof(Action<Version>));
var parameters = delegateMethod.GetMethodInfo().GetParameters();
Assert.False(parameters[0].HasDefaultValue); // Success
@edwardmeng
Copy link
Author

It can cause some wired behaviors for the Autofac integrating with DynamicProxy2 when the dependency is not registered. Since there is a class just make use of it.
https://github.com/autofac/Autofac/blob/41044d7d1a4fa277c628021537d5a12016137c3b/src/Autofac/Core/Activators/Reflection/DefaultValueParameter.cs

@danmoseley
Copy link
Member

@joshfree can you please triage and close/move to future/2.1 or assign for ZBB

tillig referenced this issue in autofac/Autofac Oct 16, 2017
dotnet/corefx#17943
dotnet/corefx#12338
dotnet/corefx#11797
@msftgits msftgits transferred this issue from dotnet/corefx Jan 31, 2020
@msftgits msftgits added this to the Future milestone Jan 31, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@steveharter
Copy link
Member

I agree that HasDefaultValue==false would be the better default in order to distinguish between an explicit default value and an implied default value other than null.

If the default value is changed to false I don't think this would be a breaking change to consumers of the IL since a null value for the DefaultProperty property seems to work fine for value types (i.e. no exception or apparent IL issue).

For example, changing the same code object to use a non-nullable int instead of Version (a reference type) works fine:

            var methodBuilder = type.DefineMethod("DoSomething", MethodAttributes.Public, CallingConventions.Standard, typeof(int), new[] { typeof(int) });
            il = methodBuilder.GetILGenerator();
            il.Emit(OpCodes.Ldarg_1);
            il.Emit(OpCodes.Ret);

along with consuming code that would try to use the default value (null) as the argument

            var typeInfo = type.CreateTypeInfo();
            var constructor = typeInfo.GetConstructor(new[] { typeof(int) });
            var parameters = constructor.GetParameters();

            var method = typeInfo.GetMethod("DoSomething", new[] { typeof(int) });
            parameters = method.GetParameters();

            Type? realType = type.CreateType();
            object obj = Activator.CreateInstance(realType, new object[] { null });

            MethodInfo mi = realType.GetMethod("DoSomething");
            object defaultValue = mi.GetParameters()[0].DefaultValue;
            // defaultValue is null
            int myInt = (int)mi.Invoke(obj, new object[] { defaultValue });
            // myInt is 0 even though the default value is "null"

cc @GrabYourPitchforks

@steveharter steveharter modified the milestones: Future, 5.0 Apr 13, 2020
@steveharter steveharter added bug and removed untriaged New issue has not been triaged by the area owner question Answer questions and provide assistance, not an issue with source code or documentation. labels Apr 13, 2020
@steveharter
Copy link
Member

Moving to future based on priority + schedule.

@steveharter steveharter modified the milestones: 5.0.0, Future Aug 11, 2020
@steveharter steveharter modified the milestones: Future, 6.0.0 Sep 30, 2020
@krwq krwq modified the milestones: 6.0.0, 7.0.0 Jun 17, 2021
@buyaa-n buyaa-n modified the milestones: 7.0.0, 8.0.0 Jul 6, 2022
@buyaa-n buyaa-n modified the milestones: 8.0.0, Future Jul 26, 2022
@steveharter steveharter added the help wanted [up-for-grabs] Good issue for external contributors label Nov 4, 2022
@steveharter steveharter modified the milestones: Future, 8.0.0 Nov 4, 2022
@buyaa-n buyaa-n added the good first issue Issue should be easy to implement, good for first-time contributors label Nov 4, 2022
@steveharter
Copy link
Member

Moving to 8.0; seems like it should be a trivial fix.

@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Apr 9, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label May 31, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Jun 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Reflection.Emit bug good first issue Issue should be easy to implement, good for first-time contributors help wanted [up-for-grabs] Good issue for external contributors
Projects
No open projects
7 participants