1

In a source generator, I'd like to determine if a member is IEnumerable or IDictionary. In the sample below, the array member returns IEnumerable, etc. from AllInterfaces, but I get zero interfaces for List<> or Dictionary<>.

    using Microsoft.CodeAnalysis;
    using Microsoft.CodeAnalysis.CSharp;
    using Microsoft.CodeAnalysis.CSharp.Syntax;

    var sourceCode = @"
                        public class ArrayOptions
                        {
                            public class ArrayItem
                            {
                                public string ProfileName { get; set; } = """";
                            }

                            public List<ArrayItem> ProfilesList { get; set; } = new List<ArrayItem>();
                            public Dictionary<string, ArrayItem> ProfilesDictionary { get; set; } = new Dictionary<string,ArrayItem>();

                            public ArrayItem[] ProfilesArray { get; set; } = Array<ArrayItem>.Empty;
                        }
                    }
                ";

    var syntaxTree = CSharpSyntaxTree.ParseText(sourceCode);

    var compilation = CSharpCompilation.Create("RoslynSample")
        .AddReferences(
            MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
            MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location))
        .AddSyntaxTrees(syntaxTree);

    var semanticModel = compilation.GetSemanticModel(syntaxTree);

    var classDeclaration = syntaxTree.GetRoot()
        .DescendantNodes()
        .OfType<ClassDeclarationSyntax>()
        .First(c => c.Identifier.Text == "ArrayOptions");

    var classSymbol = semanticModel.GetDeclaredSymbol(classDeclaration) as INamedTypeSymbol;

    var properties = classSymbol!.GetMembers().OfType<IPropertySymbol>();

    foreach (var property in properties)
    {
        Console.WriteLine($"Property: {property.Name}, Type: {property.Type}");

        // only array has any interfaces not IList or List??
        var allInterfaces = property.Type.AllInterfaces;

        foreach (var interfaceSymbol in allInterfaces)
        {
            Console.WriteLine($"  Interface: {interfaceSymbol.ToDisplayString()}");
        }
    }

1 Answer 1

2

If you check property.Type.Kind, you'll see that it says ErrorType for the first two, and ArrayType for the last. This points to the fact that something is wrong with the code.

The easiest way to figure it out is to call compilation.GetDiagnostics().

(9,36): error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
(9,85): error CS0246: The type or namespace name 'List<>' could not be found (are you missing a using directive or an assembly reference?)
(10,105): error CS0246: The type or namespace name 'Dictionary<,>' could not be found (are you missing a using directive or an assembly reference?)
(10,36): error CS0246: The type or namespace name 'Dictionary<,>' could not be found (are you missing a using directive or an assembly reference?)
(12,78): error CS0103: The name 'Array' does not exist in the current context
(14,21): error CS1022: Type or namespace definition, or end-of-file expected
error CS5001: Program does not contain a static 'Main' method suitable for an entry point

That last error on line (14) was because you have an extra closing brace } in the code.

The rest are simply missing using directives:

using System;
using System.Collections.Generic;

AllInterfaces should work, now that it can actually find the types.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.