Home General
Options

LINQPad 9 - Early Preview now available

2»

Comments

  • What's the issue with running ILSpy 8.2 with .NET 10?

    I cannot make LINQPad work with ILSpy 9. While the command-line parameter issue is easy to fix, there's another problem with their new IPC mechanism. It essentially prevents LINQPad from reliably re-using a particular instance that it created. Will need to log a feature request with ILSpy when I get a chance to get this fixed.

  • @JoeAlbahari said:
    What's the issue with running ILSpy 8.2 with .NET 10?

    Try pressing F12 on List on a line like :

    List<string> x = new();

    Or you can just run directly


    "%localappdata%\LINQPad\ILSpy8.2\ILSpy.exe" "C:\Program Files\dotnet\shared\Microsoft.NETCore.App\10.0.0-preview.5.25277.114\System.Collections.dll" /navigateTo:T:System.Collections.Generic.List`1 /separate

    The source of the line where It crashes is

    https://github.com/icsharpcode/ILSpy/blob/cf4f68bf3a4c7d78209d00f4a354dc0adc4eedcc/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs#L309

    as version is just 10.0 rather then 10.0.0

    Not sure whether it is this line that is wrong or whether version should not be detected as 10.0 but 10.0.0.

  • Trying to add some extensions using the new syntax and getting an NRE in LINQPad with no details. Works fine if it's converted to the older syntax.

    void Main()
    {
        typeof(Dictionary<string, ValueTuple<int, string, object>>).GetFriendlyName().Dump();
    }
    
    
    public static class TypeExtensions
    {
        extension(Type type)
        {
            public string GetFriendlyName()
            {
                return Impl(type);
    
                static string Impl(Type type, bool skipGeneric = false) => Type.GetTypeCode(type) switch
                {
                    TypeCode.Boolean => "bool",
                    TypeCode.Char => "char",
                    TypeCode.SByte => "sbyte",
                    TypeCode.Byte => "byte",
                    TypeCode.Int16 => "short",
                    TypeCode.UInt16 => "ushort",
                    TypeCode.Int32 => "int",
                    TypeCode.UInt32 => "uint",
                    TypeCode.Int64 => "long",
                    TypeCode.UInt64 => "ulong",
                    TypeCode.Single => "float",
                    TypeCode.Double => "double",
                    TypeCode.Decimal => "decimal",
                    TypeCode.String => "string",
                    TypeCode.Object when type == typeof(object) => "object",
                    _ => type switch
                    {
                        { IsGenericType: true } when type.GetGenericTypeDefinition() == typeof(Nullable<>)
                            => $"{Impl(Nullable.GetUnderlyingType(type)!, skipGeneric)}?",
                        { IsGenericType: true } when typeof(ValueTuple).GetInterface("IValueTupleInternal")!.IsAssignableFrom(type)
                            => ValueTupleName(type),
                        { IsGenericType: true } when !skipGeneric => GenericTypeName(type),
                        { IsNested: true } => $"{Impl(type.DeclaringType!, skipGeneric)}+{type.Name}",
                        { IsArray: true } => $"{Impl(type.GetElementType()!, skipGeneric)}[]",
                        { IsByRef: true } => $"out {Impl(type.GetElementType()!, skipGeneric)}",
                        { IsPointer: true } => $"{Impl(type.GetElementType()!, skipGeneric)}*",
                        _ => $"{type!.Namespace}.{type.Name}",
                    },
                };
                static string ValueTupleName(Type tupleType)
                {
                    // value tuples in practice will be generic and have at least 2 type parameters
                    // though, non-generic and 1-tuple is possible, we'll ignore
                    return $"({string.Join(", ", tupleType.GenericTypeArguments.Select(t => Impl(t)))})";
                }
                static string GenericTypeName(Type genericType)
                {
                    var typeParameters = new Queue<string?>(genericType.GenericTypeArguments.Select(t => Impl(t)));
                    var nestedName = Impl(genericType, skipGeneric: true)!;
                    return Regex.Replace(nestedName, @"`(\d+)", m =>
                    {
                        var replacements = Enumerable.Range(0, int.Parse(m.Groups[1].Value))
                            .Select(_ => typeParameters.Dequeue());
                        return $"<{string.Join(", ", replacements)}>";
                    });
                }
            }
        }
    }
    
  • This should now be fixed with the latest Roslyn update in 9.1.5

Sign In or Register to comment.