How do I generate a constructor from class fields using Visual Studio (and/or ReSharper)?
Solution 1
ReSharper offers a Generate Constructor tool where you can select any field/properties that you want initialized. I use the Alt + Ins hot-key to access this.
Solution 2
In Visual Studio 2015 Update3 I have this feature.
Just by highlighting properties and then press Ctrl + . and then press Generate Constructor.
For example, if you've highlighted two properties it will suggest you to create a constructor with two parameters and if you've selected three it will suggest one with three parameters and so on.
It also works with Visual Studio 2017 and 2019.
Solution 3
C# added a new feature in Visual Studio 2010 called generate from usage. The intent is to generate the standard code from a usage pattern. One of the features is generating a constructor based off an initialization pattern.
The feature is accessible via the smart tag that will appear when the pattern is detected.
For example, let’s say I have the following class
class MyType {
}
And I write the following in my application
var v1 = new MyType(42);
A constructor taking an int
does not exist so a smart tag will show up and one of the options will be "Generate constructor stub". Selecting that will modify the code for MyType
to be the following.
class MyType {
private int p;
public MyType(int p) {
// TODO: Complete member initialization
this.p = p;
}
}
Solution 4
As of Visual Studio 2017, this looks to be a built-in feature. Hit Ctrl + . while your cursor is in the class body, and select "Generate Constructor" from the Quick Actions and Refactorings dropdown.
Solution 5
You could write a macro to do this -- you would use Visual Studio's parser to retrieve information about the class's members.
I wrote a similar macro. (I'll share the code below). The macro I wrote is for copying forward all of the constructors in a base class when you inherit from it (useful for classes like Exception that have lots of overloads on the ctor).
Here's my macro (again, it doesn't solve your problem, but you can probably modify to do what you want)
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports EnvDTE100
Imports System.Diagnostics
Public Module ConstructorEditor
Public Sub StubConstructors()
'adds stubs for all of the constructors in the current class's base class
Dim selection As TextSelection = DTE.ActiveDocument.Selection
Dim classInfo As CodeClass2 = GetClassElement()
If classInfo Is Nothing Then
System.Windows.Forms.MessageBox.Show("No class was found surrounding the cursor. Make sure that this file compiles and try again.", "Error")
Return
End If
If classInfo.Bases.Count = 0 Then
System.Windows.Forms.MessageBox.Show("No parent class was found for this class. Make sure that this file, and any file containing parent classes compiles and try again")
Return
End If
'setting up an undo context -- one ctrl+z undoes everything
Dim closeUndoContext As Boolean = False
If DTE.UndoContext.IsOpen = False Then
closeUndoContext = True
DTE.UndoContext.Open("StubConstructorsContext", False)
End If
Try
Dim parentInfo As CodeClass2 = classInfo.Bases.Item(1)
Dim childConstructors As System.Collections.Generic.List(Of CodeFunction2) = GetConstructors(classInfo)
Dim parentConstructors As System.Collections.Generic.List(Of CodeFunction2) = GetConstructors(parentInfo)
For Each constructor As CodeFunction2 In parentConstructors
If Not MatchingSignatureExists(constructor, childConstructors) Then
' we only want to create ctor stubs for ctors that are missing
' note: a dictionary could be more efficient, but I doubt most classes will have more than 4 or 5 ctors...
StubConstructor(classInfo, constructor)
End If
Next
Finally
If closeUndoContext Then
DTE.UndoContext.Close()
End If
End Try
End Sub
Private Function GetConstructors(ByVal classInfo As CodeClass2) As System.Collections.Generic.List(Of CodeFunction2)
' return a list of all of the constructors in the specified class
Dim result As System.Collections.Generic.List(Of CodeFunction2) = New System.Collections.Generic.List(Of CodeFunction2)
Dim func As CodeFunction2
For Each member As CodeElement2 In classInfo.Members
' members collection has all class members. filter out just the function members, and then of the functions, grab just the ctors
func = TryCast(member, CodeFunction2)
If func Is Nothing Then Continue For
If func.FunctionKind = vsCMFunction.vsCMFunctionConstructor Then
result.Add(func)
End If
Next
Return result
End Function
Private Function MatchingSignatureExists(ByVal searchFunction As CodeFunction2, ByVal functions As System.Collections.Generic.List(Of CodeFunction2)) As Boolean
' given a function (searchFunction), searches a list of functions where the function signatures (not necessarily the names) match
' return null if no match is found, otherwise returns first match
For Each func As CodeFunction In functions
If func.Parameters.Count <> searchFunction.Parameters.Count Then Continue For
Dim searchParam As CodeParameter2
Dim funcParam As CodeParameter2
Dim match As Boolean = True
For count As Integer = 1 To searchFunction.Parameters.Count
searchParam = searchFunction.Parameters.Item(count)
funcParam = func.Parameters.Item(count)
If searchParam.Type.AsFullName <> funcParam.Type.AsFullName Then
match = False
Exit For
End If
Next
If match Then
Return True
End If
Next
' no match found
Return False
End Function
Private Sub StubConstructor(ByVal classInfo As CodeClass2, ByVal parentConstructor As CodeFunction2)
' adds a constructor to the current class, based upon the parentConstructor that is passed in
' highly inefficient hack to position the ctor where I want it (after the last ctor in the class, if there is another ctor
' note that passing zero as the position (put the ctor first) caused some problems when we were adding ctors to classes that already had ctors
Dim position As Object
Dim ctors As System.Collections.Generic.List(Of CodeFunction2) = GetConstructors(classInfo)
If ctors.Count = 0 Then
position = 0
Else
position = ctors.Item(ctors.Count - 1)
End If
' if there are no other ctors, put this one at the top
Dim ctor As CodeFunction2 = classInfo.AddFunction(classInfo.Name, vsCMFunction.vsCMFunctionConstructor, vsCMTypeRef.vsCMTypeRefVoid, position, parentConstructor.Access)
Dim baseCall As String = ":base("
Dim separator As String = ""
For Each parameter As CodeParameter2 In parentConstructor.Parameters
ctor.AddParameter(parameter.Name, parameter.Type, -1)
baseCall += separator + parameter.Name
separator = ", "
Next
baseCall += ")"
' and 1 sad hack -- appears to be no way to programmatically add the :base() calls without using direct string manipulation
Dim startPoint As TextPoint = ctor.GetStartPoint()
Dim endOfSignature As EditPoint = startPoint.CreateEditPoint()
endOfSignature.EndOfLine()
endOfSignature.Insert(baseCall)
startPoint.CreateEditPoint().SmartFormat(endOfSignature)
End Sub
Private Function GetClassElement() As CodeClass2
'returns a CodeClass2 element representing the class that the cursor is within, or null if there is no class
Try
Dim selection As TextSelection = DTE.ActiveDocument.Selection
Dim fileCodeModel As FileCodeModel2 = DTE.ActiveDocument.ProjectItem.FileCodeModel
Dim element As CodeElement2 = fileCodeModel.CodeElementFromPoint(selection.TopPoint, vsCMElement.vsCMElementClass)
Return element
Catch
Return Nothing
End Try
End Function
End Module
Related videos on Youtube
Comments
-
Elijah over 3 years
I've gotten accustomed to many of the Java IDEs (Eclipse, NetBeans, and IntelliJ IDEA) providing you with a command to generate a default constructor for a class based on the fields in the class.
For example:
public class Example { public decimal MyNumber { get; set; } public string Description { get; set; } public int SomeInteger { get; set; } // ↓↓↓ This is what I want generated ↓↓↓ public Example(decimal myNumber, string description, int someInteger) { MyNumber = myNumber; Description = description; SomeInteger = someInteger; } }
Having a constructor populate all of the fields of an object is such a common task in most OOP languages, I'm assuming that there is a some way for me to save time writing this boilerplate code in C#. I'm new to the C# world, so I'm wondering if I'm missing something fundamental about the language? Is there some option in Visual Studio that is obvious?
-
Elijah almost 14 yearsThat answers the question for me in terms of "getting it done." However, there is no support for it in VS2010 directly, right?
-
James Kolpack almost 14 yearsLike Jared mentions below, VS2010 added a "Generate from usage" tool, but as far as I can tell, there's no way to generate a constructor based on fields that are already in the class. If you try to instantiate the class with a signature that doesn't match any existing ones, it will offer to generate that constructor for you.
-
LTR almost 12 yearsThere is an operator missing: " If searchParam.Type.AsFullName funcParam.Type.AsFullName Then" should be " If searchParam.Type.AsFullName = funcParam.Type.AsFullName Then"
-
JMarsch almost 12 years@LTR Great catch -- except it is supposed to be "If searchParam.Type.AsFullName <> funcParam.Type.AsFullName ". I missed the escape on the angle brackets -- they appeared in the editor, but not in the view. Thanks!
-
Brett almost 11 yearsOh wow, I know this is a fairly old question but I've only just discovered this!
-
Joel Peltonen about 10 yearsThe second command is a shortcut to the class view, is it not? Or is this tip not about Visual Studio 2010?
-
cedd over 9 yearsI had to split the line:"If Not String.IsNullOrEmpty(parameterName) And Not visitedNames.ContainsKey(parameterName) Then" into two lines to avoid a null reference exception:
-
arkon about 8 yearsYou should probably mention ReSharper is not free.
-
The 0bserver about 7 yearsHey, this worked for me in Visual Studio 2015 community. Not sure how this isn't very publically known, but this is nice. Thanks. :)
-
Timo about 7 yearsThat is perfect. The work this could have saved if I'd read it the day you posted it... xD
-
Chris Sinclair almost 7 yearsFor what it's worth, the feature doesn't pop up if you use C# 6 read-only properties. (e.g.,
public int Age { get; }
) They need to have at setters specified, even if temporarily, for the option to be available. Tested in VS2015 Community; not sure if this has been fixed in VS2017. -
Pouya Samie almost 7 years@chris when you have not setter so how can use that in constructor? you should use the underlying property
-
Chris Sinclair almost 7 years@PouyaSamie: In C# 6.0, readonly auto-properties can be assigned in the constructor. See this for an example: github.com/dotnet/roslyn/wiki/…
-
Dork almost 7 yearsIt generate constructor above properties. Is it possible to set it to generate constructor below properties?
-
Pouya Samie almost 7 years@Dork sorry i did not find anyway for that
-
Sinjai almost 7 yearsIt would be nice if this could be updated to be the selected answer. I almost started looking into getting ReSharper. ReSharper's great, but KISS and all. Always scroll down and check time stamps!
-
Václav Holuša over 6 yearsThis is the perfect solution! I would mark this the real solution!
-
Prabhakar over 6 yearsThis is great! How do I generate a noargs constructor?
-
Pouya Samie over 6 years@Prabhakar you can use the "ctor" snippet. just write ctor then push tab twice.
-
ymerdrengene over 6 yearsFor Mac OS (couldn't find key shortcut tho..): Highlight properties --> Right click --> Quick fix --> Generate constructor
-
edencorbin about 6 yearsTime saver yeahhhhh!
-
Peter Mortensen about 5 yearsCodePlex has been shut down (but the link is currently still somewhat valid, with a downloadable archive). But perhaps try to update the link (if the project has been moved elsewhere). And/or take steps to prevent a disaster if the current link becomes broken in the future.
-
ashlar64 almost 4 yearsThis needs to be the answer instead of purchasing Resharper. I can't believe I have been making large constructors by hand for the last 5 years when I didn't need to be. ARGH!
-
Soenhay over 3 yearsWorks in VS2019