3

I have scratched my head for over a day on this:

Essentially I am attempting to build an Add-In for Visual Studio 2012 that does the following:

Take the variable name that is currently selected, go and find the class that it is an instance of, then type the veriable.property for each property on its own line:

BEFORE:

eg. (Consider myPerson is selected)

int CountPerson(Person myPerson)
{
    *myPerson*
}

AFTER:

int CountPerson(Person myPerson)
{
    myPerson.Name
    myPerson.Surname
    myPerson.Age
}

I have asked a similar question here on stackoverflow, and received the answer that I am now pursuing. Visual Studio dump all properties of class into editor

Here is the source code so far:

using EnvDTE;
using EnvDTE80;
using System;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;


public class C : VisualCommanderExt.ICommand
{
    public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package) 
    {
        EnvDTE.TextSelection ts = DTE.ActiveWindow.Selection as EnvDTE.TextSelection;
        if (ts == null)
            return;

        EnvDTE.CodeClass codeClass = ts.ActivePoint.CodeElement[vsCMElement.vsCMElementClass]   as     EnvDTE.CodeClass;
        if (codeClass == null)
            return;

        string properties = "";
        foreach (CodeElement elem in codeClass.Members)
        {
            if (elem.Kind == vsCMElement.vsCMElementProperty)
                properties += elem.Name + System.Environment.NewLine;
        }
        ts.Text = properties;   

    }
}

This works perfectly fine, except that it completely ignores the selected text, and instead prints the properties of the current class. I need the properties of the class of the variable I am selecting.

I will live with typing "Person" instead of |myPerson" if that will make things easier.

I have found the following links on the internet, but was unable to implement the logic: http://blogs.clariusconsulting.net/kzu/how-to-get-a-system-type-from-an-envdte-codetyperef-or-envdte-codeclass/ http://www.visualstudioextensibility.com/2008/03/06/how-do-i-get-a-system-type-from-a-type-name/

They may help you with helping me?

Community
  • 1
  • 1
user230910
  • 2,353
  • 2
  • 28
  • 50
  • Have you been successful with creating your Extension? Have you put it onto the Visual Studio gallery yet? – Marcel Apr 16 '15 at 11:44
  • The code below is as far as I managed to get, I eventually gave up and lived without it – user230910 Apr 16 '15 at 12:10
  • If you would mind helping me along some more? – user230910 Apr 16 '15 at 12:14
  • I have made an Extension to Visual Studio myself, where I get the class name and method name where the current selection lies in. I have the source on GitHub, it's called [CopyForReview](https://github.com/suterma/CopyForReview) Probably browsing it's source might help you out? – Marcel Apr 16 '15 at 12:24

2 Answers2

3

You can set the cursor on a function parameter name in the function definition line and generate properties list with the following code:

(add a reference to Microsoft.VisualStudio.Shell.Design)

public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package) 
{
    EnvDTE.TextSelection ts = DTE.ActiveWindow.Selection as EnvDTE.TextSelection;
    if (ts == null)
        return;

    EnvDTE.CodeParameter codeParam = ts.ActivePoint.CodeElement[vsCMElement.vsCMElementParameter] as EnvDTE.CodeParameter;
    if (codeParam == null)
        return;

    System.Type tClass = GetTypeByName(DTE, package, codeParam.Type.AsFullName);
    string properties = "";
    foreach (var p in tClass.GetProperties())
    {
            properties += codeParam.Name + "." + p.Name + System.Environment.NewLine;
    }
    System.Windows.Clipboard.SetText(properties);
    System.Windows.MessageBox.Show(properties);
}

private System.Type GetTypeByName(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package, string name)
{
    System.IServiceProvider serviceProvider = package as System.IServiceProvider;
    Microsoft.VisualStudio.Shell.Design.DynamicTypeService typeService = 
        serviceProvider.GetService(typeof(Microsoft.VisualStudio.Shell.Design.DynamicTypeService)) as
        Microsoft.VisualStudio.Shell.Design.DynamicTypeService;

    Microsoft.VisualStudio.Shell.Interop.IVsSolution sln = 
        serviceProvider.GetService(typeof(Microsoft.VisualStudio.Shell.Interop.IVsSolution)) as
        Microsoft.VisualStudio.Shell.Interop.IVsSolution;

    Microsoft.VisualStudio.Shell.Interop.IVsHierarchy hier;
    sln.GetProjectOfUniqueName(DTE.ActiveDocument.ProjectItem.ContainingProject.UniqueName, out hier);

    return typeService.GetTypeResolutionService(hier).GetType(name, true);
}
Sergey Vlasov
  • 26,641
  • 3
  • 64
  • 66
  • wow, this is brilliant, very close to what i'm looking for. Only difference is the placing of the cursor and the output location. Why does it have to be on the function line? – user230910 Sep 10 '14 at 09:03
  • Ok I managed to get the result into the method: `ts.LineDown();ts.LineDown();ts.StartOfLine();ts.Insert(properties);` – user230910 Sep 10 '14 at 09:18
  • So the only remaining problem is to use the variable selected in the code, instead of forcing the user to select a function parameter – user230910 Sep 10 '14 at 09:19
  • @user230910: Two line downs to move to function body? What if opening `{` is on the same line as method signature? – Andriy Tylychko Sep 10 '14 at 11:25
  • @user230910 Visual Studio code model doesn't support local variables, that's why I used a function declaration. Maybe it is possible to go from the selected variable name to function parameter with additional command code. – Sergey Vlasov Sep 10 '14 at 13:44
  • ok i have accepted your answer. I will add another answer to document my continued efforts to do this completely – user230910 Sep 11 '14 at 04:55
1

Ok, thanks to Sergey above I now have the below code that answers most of my question:

using EnvDTE;
using EnvDTE80;
using System;

public class C : VisualCommanderExt.ICommand
{
        public void Run(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package) 
        {
            EnvDTE.TextSelection ts = DTE.ActiveWindow.Selection as EnvDTE.TextSelection;
            if (ts == null)
                    throw new Exception("No Selection");

                EnvDTE.CodeParameter codeParam = ts.ActivePoint.CodeElement[vsCMElement.vsCMElementParameter] as EnvDTE.CodeParameter;
                if (codeParam == null)
                    throw new Exception("Not Parameter");

                System.Type tClass = GetTypeByName(DTE, package, codeParam.Type.AsFullName);
                string properties = System.Environment.NewLine;
                foreach (var p in tClass.GetProperties())
                {
                    properties += codeParam.Name + "." + p.Name + System.Environment.NewLine;
                }

                // Move into the method and dump the properties there
                ts.FindText("{");
                ts.Insert("{" + properties);
            }


    private System.Type GetTypeByName(EnvDTE80.DTE2 DTE, Microsoft.VisualStudio.Shell.Package package, string name)
    {
        System.IServiceProvider serviceProvider = package as System.IServiceProvider;
        Microsoft.VisualStudio.Shell.Design.DynamicTypeService typeService = 
            serviceProvider.GetService(typeof(Microsoft.VisualStudio.Shell.Design.DynamicTypeService)) as
                Microsoft.VisualStudio.Shell.Design.DynamicTypeService;

        Microsoft.VisualStudio.Shell.Interop.IVsSolution sln = serviceProvider.GetService(typeof(Microsoft.VisualStudio.Shell.Interop.IVsSolution)) as
            Microsoft.VisualStudio.Shell.Interop.IVsSolution;

        Microsoft.VisualStudio.Shell.Interop.IVsHierarchy hier;
        sln.GetProjectOfUniqueName(DTE.ActiveDocument.ProjectItem.ContainingProject.UniqueName, out hier);

        return typeService.GetTypeResolutionService(hier).GetType(name, true);
    }
}

Current Issues:

    * It doesnt work for a variable in the code only for function parameters

I found this which might help: (The code is waaaay beyond my skills though) Auto generate properties when creating object

Community
  • 1
  • 1
user230910
  • 2,353
  • 2
  • 28
  • 50