Getting a list of constructor overloads

Topics: APIs
May 19, 2014 at 6:42 PM
Edited May 19, 2014 at 6:46 PM
Hi folks,

I'm having a bit of trouble getting a list of possible constructor overloads from Roslyn.

For method overloads, i.e. for something like:
Console.WriteLine();
I'm able to use GetSymbolInfo on the SemanticModel for that InvocationExpressionSyntax, which returns me the info for the WriteLine() symbol, upon which I can loop over GetMembers() to get all the possible overloads. This looks a bit like:
completions = compilation.GetSemanticModel(tree).GetSymbolInfo(invocationNode);
methodName = completions.Symbol.Name;

foreach(IMethodSymbol overload in completions.Symbol.GetMembers(methodName))
{
    //Do stuff here
}
However, for something like:
var thing = new Action();
I don't get any symbol information at all from the ObjectCreationSyntax for GetSymbolInfo. How can I go about getting the possible constructor overloads given that piece of the syntax tree above?

Thanks,
Matt
May 20, 2014 at 8:07 PM
I assume the Action you have there is the Action delegate. If so, this is already reported, although I'm not sure if its actually a bug (seems like it though): https://roslyn.codeplex.com/workitem/66
May 21, 2014 at 8:51 PM
Edited May 21, 2014 at 8:52 PM
Yeah, I think that issue definitely relates.

Additionally (and perhaps this is the reason for the issue), when I manually use something like:
 if (node is ObjectCreationExpressionSyntax)
 {
       members = compilation.GetSemanticModel(tree)
            .GetTypeInfo(node).Type
            .GetMembers(".ctor");
 }
I get two possible parameters for the constructor: Object object and IntPtr method. So, I'm not sure how to handle getting delegate type information in general to get to the result that VS does, which is 'void () target'. Maybe those are hard wired?
May 22, 2014 at 3:24 PM
I believe that signature is how things are actually implemented internally. So for example, if I have something like this:
class Program
{
    static void Main(string[] args)
    {
        var x = new Action(new Program().X);
        var y = new Action(Y);
    }

    void X() { }
    static void Y() { }
}
What I'm really doing is something like this:
var x = new Action(new Program(), [address of] X);
var y = new Action(null, [address of] Y);
This can be seen by inspecting the IL that gets generated for the Main method in IL DASM:
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       32 (0x20)
  .maxstack  2
  .locals init ([0] class [mscorlib]System.Action x,
           [1] class [mscorlib]System.Action y)
  IL_0000:  nop
  IL_0001:  newobj     instance void ConsoleApplication21.Program::.ctor()
  IL_0006:  ldftn      instance void ConsoleApplication21.Program::X()
  IL_000c:  newobj     instance void [mscorlib]System.Action::.ctor(object,
                                                                    native int)
  IL_0011:  stloc.0
  IL_0012:  ldnull
  IL_0013:  ldftn      void ConsoleApplication21.Program::Y()
  IL_0019:  newobj     instance void [mscorlib]System.Action::.ctor(object,
                                                                    native int)
  IL_001e:  stloc.1
  IL_001f:  ret
} // end of method Program::Main
So what Roslyn seems to be reporting is the symbol semantics needed by the .NET framework, but not those needed by the C# language, which is probably what it should really be reporting. In the C# language, there is only one constructor overload to delegates and they take one argument: "a method group, an anonymous function or a value of either the compile time type dynamic or a delegate-type" (from the C# 5.0 specification, section 7.6.10.5). That is probably how the constructor symbol should be reported by the semantic model.