NeVeSpl / NTypewriter

File/code generator using Scriban text templates populated with C# code metadata from Roslyn API.
https://nevespl.github.io/NTypewriter/
MIT License
126 stars 25 forks source link

How to join arrays without losing type information? #120

Open jons-bakerhill opened 5 months ago

jons-bakerhill commented 5 months ago

I have the following template code

{{- publicProperties = class.Properties | Custom.HasPublicSetter
    if (class.BaseClass?.Properties)
        publicProperties = Array.AddRange(publicProperties, class.BaseClass?.Properties | Custom.HasPublicSetter)
    end
    referencedClassTypes = publicProperties | Custom.GetClassTypes
}}

where GetClassTypes is defined as public static IEnumerable<IType> GetClassTypes(IEnumerable<IProperty> publicProperties)

When rendering I get the error "Unable to convert type range to IEnumerable<IProperty>"

Is there a way to join arrays and keep type information?

jons-bakerhill commented 5 months ago

I got things to work via the code below, would be nice to know if there's a better way though.

        public static IEnumerable<IType> GetClassTypes(object publicProperties)
        {
            IEnumerable<IProperty> cast = publicProperties as IEnumerable<IProperty>
                ?? (publicProperties as IEnumerable<object>).Cast<IProperty>();

            if (cast == null)
            {
                System.Diagnostics.Debugger.Launch();
            }

            return cast
                    .Select(x => x.Type.Unwrap())
                    .Where(x => !x.IsPrimitive && !x.IsValueType || x.IsEnum)
                    .Distinct()
                    .ToArray();
        }
NeVeSpl commented 5 months ago

Scriban is a typeless language and its built-in functions do not care about returning the correct type.

As an alternative to what you already got, you could make a custom function to select public properties that will return IEnumerable<IProperty>, that way you should be able to use the original/typed version of GetClassTypes(IEnumerable<IProperty> publicProperties).