Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICSharpCode.Decompiler.TypeSystem.IType property values should match System.Reflection.Type property values #3170

Open
cwellsx opened this issue Mar 3, 2024 · 0 comments
Labels
Enhancement Areas for improvement

Comments

@cwellsx
Copy link

cwellsx commented Mar 3, 2024

I'm viewing type information in two ways:

  • Using IType from the ICSharpCode.Decompiler APIs
  • Using Type from MetaDataLoadContext.LoadFromAssemblyPath(path).GetTypes()

I notice the your IType API is very similar to the Type API but not identical.
And I don't know whether the difference is on purpose but it troubles me they're not quite interchangeable.

For reference, here's my record into which I load the property values:

    public record TypeId(
        string? AssemblyName,
        string? Namespace,
        string Name,
        Values<TypeId>? GenericTypeArguments,
        TypeId? DeclaringType
        );

Here's my initializing that from a System.Reflection.Type instance

        static TypeId GetTypeId(Type type)
        {
            TypeId[]? GetGenericTypeArguments()
            {
                var types = type.GenericTypeArguments;
                return (types.Length == 0) ? null : types.Select(GetTypeId).ToArray();
            }
            return new TypeId(
                AssemblyName: type.Assembly.GetName().Name,
                Namespace: type.Namespace,
                Name: type.Name,
                GenericTypeArguments: GetGenericTypeArguments(),
                DeclaringType: type.DeclaringType != null ? GetTypeId(type.DeclaringType) : null
            );
        }

Here's my initializing that from your IType instance

        static TypeId Transform(this IType type)
        {
            var elementType = (type as TypeWithElementType)?.ElementType ?? type;
            var nameSuffix = (type as TypeWithElementType)?.NameSuffix ?? string.Empty;
            var assemblyName = elementType.GetDefinition()?.ParentModule?.AssemblyName;
            // want a name like "KeyValuePair`2[]" (i.e. with generic arity appended) and not just "KeyValuePair[]"
            var name = elementType.GetDefinition()?.MetadataName ?? type.Name;
            // we have the name of the element not the type, so add the suffix
            name += nameSuffix;

            return new TypeId(
                assemblyName,
                type.Namespace == string.Empty ? null : type.Namespace,
                name,
                type.TypeArguments.Select(Transform).ToArrayOrNull(),
                type.DeclaringType?.Transform()
               );
        }

In summary the differences I've found so far (after only one day of test-and-debugging) are as follows.

  1. The AssemblyName when the type is an array -- you correctly (i.e. same as Type) display the name e.g. Foo[], and the namespace (of Foo), but not the name of the assembly from which Foo is loaded -- so instead I must fetch that from your ElementType property.
  2. The Namespace, when there isn't one -- you return an empty string, Type returns null.
  3. Whether the name of the type is e.g. KeyValuePair or KeyValuePair2`
@cwellsx cwellsx added the Enhancement Areas for improvement label Mar 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement Areas for improvement
Projects
None yet
Development

No branches or pull requests

1 participant