How do I generate a constructor from class fields using Visual Studio (and/or ReSharper)?

161,814

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.

Auto generate shortcut visualisation

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

Share:
161,814

Related videos on Youtube

Elijah
Author by

Elijah

Solutions engineer at Joyent.

Updated on January 21, 2021

Comments

  • Elijah
    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
    Elijah almost 14 years
    That answers the question for me in terms of "getting it done." However, there is no support for it in VS2010 directly, right?
  • James Kolpack
    James Kolpack almost 14 years
    Like 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
    LTR almost 12 years
    There is an operator missing: " If searchParam.Type.AsFullName funcParam.Type.AsFullName Then" should be " If searchParam.Type.AsFullName = funcParam.Type.AsFullName Then"
  • JMarsch
    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
    Brett almost 11 years
    Oh wow, I know this is a fairly old question but I've only just discovered this!
  • Joel Peltonen
    Joel Peltonen about 10 years
    The second command is a shortcut to the class view, is it not? Or is this tip not about Visual Studio 2010?
  • cedd
    cedd over 9 years
    I 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
    arkon about 8 years
    You should probably mention ReSharper is not free.
  • The 0bserver
    The 0bserver about 7 years
    Hey, this worked for me in Visual Studio 2015 community. Not sure how this isn't very publically known, but this is nice. Thanks. :)
  • Timo
    Timo about 7 years
    That is perfect. The work this could have saved if I'd read it the day you posted it... xD
  • Chris Sinclair
    Chris Sinclair almost 7 years
    For 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
    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
    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
    Dork almost 7 years
    It generate constructor above properties. Is it possible to set it to generate constructor below properties?
  • Pouya Samie
    Pouya Samie almost 7 years
    @Dork sorry i did not find anyway for that
  • Sinjai
    Sinjai almost 7 years
    It 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
    Václav Holuša over 6 years
    This is the perfect solution! I would mark this the real solution!
  • Prabhakar
    Prabhakar over 6 years
    This is great! How do I generate a noargs constructor?
  • Pouya Samie
    Pouya Samie over 6 years
    @Prabhakar you can use the "ctor" snippet. just write ctor then push tab twice.
  • ymerdrengene
    ymerdrengene over 6 years
    For Mac OS (couldn't find key shortcut tho..): Highlight properties --> Right click --> Quick fix --> Generate constructor
  • edencorbin
    edencorbin about 6 years
    Time saver yeahhhhh!
  • Peter Mortensen
    Peter Mortensen about 5 years
    CodePlex 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
    ashlar64 almost 4 years
    This 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
    Soenhay over 3 years
    Works in VS2019