You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Cannot implement Option because the only constructors are internal #1889
A recent change in 2.0-beta4 removed the public constructors for Option. Because the constructors are declared with internal accessibility, 3rd party libraries and applications can no longer extend the abstract Option class.
The following constructors should be changed to protected accessibility to allow custom extensions of Option:
@jonsequitur I appreciate the response! I've written a library that provides an attribute-based framework for declaring and configuring a System.CommandLine application. Since it's using reflection to dynamically build the arguments and options at runtime, we can't use the generic Option<T> class.
I agree with the original change to remove the public constructors (in an effort to reduce the surface area of the API), but the internal accessibility of the Option constructors seems like an oversight since Argument already has constructors with protected accessibility.
Please let me know if you have any questions or need more info.
Since it's using reflection to dynamically build the arguments and options at runtime, we can't use the generic Option<T> class.
Can't you use typeof(Option<>).MakeGenericType(type) to find the Option<T> type, and then Activator.CreateInstance or some other reflection to invoke the constructor?
Can't you use typeof(Option<>).[MakeGenericType](https://learn.microsoft.com/dotnet/api/system.type.makegenerictype?view=netstandard-2.0)(_type_) to find the Option type, and then Activator.CreateInstance or some other reflection to invoke the constructor?
@KalleOlaviNiemitalo I was able to use Activator.CreateInstance like you mentioned above as a workaround. However, I still disagree with the API design of having a public abstract class that cannot be implemented by third parties. If the goal is to limit the surface area of this API exclusively to Option{T} and Argument{T}for performance reasons, I'd suggest that Option and Argument be made fully internal and to add new IOption and IArgument interfaces for composition.
On a separate note, I do agree with the spirit of #1638. I will look into converting my project to use source generators rather than runtime reflection for the parser configuration.
public abstract class that cannot be implemented by third parties
CompletionContext has the same restriction. I think that's even worse because its derived classes are internal so users cannot implement custom [suggest]-like directives.
I have exactly same problem as Tom. I have attributes which are then translated to Options and Arguments:
[Command("build",Description="Runs build process")]publicclassBuildCommand{publicintExecute([Argument("Project root directory")]stringrootDir=".",[Option("Output directory","-o")]stringoutDir="Build",[Option("Build configuration name","-c")]stringconfiguration="Release",[Option("Target operating system [default: current OS]","--os")]stringoperatingSystem=null,[Option("Solution directory")]stringsolutionDir="Source",[Option("Release directory")]stringreleaseDir="Release",[Option("A version applied to all projects")]stringversion=null,[Option("A version suffix applied to all projects")]stringversionSuffix=null)
I just can't understand why I can't just create an Option or Argument with Type parameter. If you want it abstract - fine. Just let me create my own implementation which allow me to do this. Besides Argument have protected constructors and Option doesn't.
Can't you use typeof(Option<>).MakeGenericType(type) to find the Option type, and then Activator.CreateInstance or some other reflection to invoke the constructor?
I'm aware of that, but I think this way of creating objects should be avoided at all costs. It's enough to say, that changes in constructor of Option will generate errors on runtime instead of compilation errors.
Activity
jonsequitur commentedon Nov 7, 2022
We're trying to reduce the surface area of the API so I would want to consider a change like this carefully.
I'm curious about the use case. Is there a reason that inheriting
Option<T>doesn't work for you?tom-mckinney commentedon Nov 9, 2022
@jonsequitur I appreciate the response! I've written a library that provides an attribute-based framework for declaring and configuring a
System.CommandLineapplication. Since it's using reflection to dynamically build the arguments and options at runtime, we can't use the genericOption<T>class.I agree with the original change to remove the
publicconstructors (in an effort to reduce the surface area of the API), but theinternalaccessibility of theOptionconstructors seems like an oversight sinceArgumentalready has constructors withprotectedaccessibility.Please let me know if you have any questions or need more info.
KalleOlaviNiemitalo commentedon Nov 9, 2022
Can't you use
typeof(Option<>).MakeGenericType(type)to find the Option<T> type, and then Activator.CreateInstance or some other reflection to invoke the constructor?tom-mckinney commentedon Nov 15, 2022
@KalleOlaviNiemitalo I was able to use
Activator.CreateInstancelike you mentioned above as a workaround. However, I still disagree with the API design of having a public abstract class that cannot be implemented by third parties. If the goal is to limit the surface area of this API exclusively toOption{T}andArgument{T}for performance reasons, I'd suggest thatOptionandArgumentbe made fully internal and to add newIOptionandIArgumentinterfaces for composition.On a separate note, I do agree with the spirit of #1638. I will look into converting my project to use source generators rather than runtime reflection for the parser configuration.
KalleOlaviNiemitalo commentedon Nov 15, 2022
CompletionContext has the same restriction. I think that's even worse because its derived classes are internal so users cannot implement custom
[suggest]-like directives.pgolinski commentedon Jan 19, 2023
I have exactly same problem as Tom. I have attributes which are then translated to Options and Arguments:
I just can't understand why I can't just create an Option or Argument with Type parameter. If you want it abstract - fine. Just let me create my own implementation which allow me to do this. Besides Argument have protected constructors and Option doesn't.
I'm aware of that, but I think this way of creating objects should be avoided at all costs. It's enough to say, that changes in constructor of Option will generate errors on runtime instead of compilation errors.
jonsequitur commentedon Jan 15, 2026
Optionis abstract and now has a protected constructor.