KEMBAR78
[API Proposal]: New AssemblyName-like type for TypeName parsing · Issue #100867 · dotnet/runtime · GitHub
Skip to content

[API Proposal]: New AssemblyName-like type for TypeName parsing #100867

@adamsitnik

Description

@adamsitnik

Background and Motivation

While working on the implementation of TypeName API (#97566), it turned out that it's impossible to set AssemblyName.CultureName without allocating a CultrueInfo instance (using public NS2.0 compatibile APIs).

set => _cultureInfo = (value == null) ? null : new CultureInfo(value);

The type name parser needs to support parsing from untrusted input and such non-predefined culture name may be used as a vector of attack, so the existing AssemblyName is not suitable for our needs.

Since AssemblyName suffers from some other design issues (mutability, a LOT of obsolete properties), I would like to introduce a new, immutable, lightweight version of AssemblyName type.

Proposed API

It's a concept and I need the help of API review board to choose the right name. Some of my ideas: ReadOnlyAssemblyName, AssemblyId, LibraryName.

namespace System.Reflection.Metadata;

public sealed class AssemblyNameInfo : IEquatable<AssemblyNameInfo>
{
    public AssemblyNameInfo(string name, Version? version = null, string? cultureName = null, AssemblyNameFlags flags = AssemblyNameFlags.None,
   Collections.Immutable.ImmutableArray<byte> publicKeyOrToken = default);
    public string Name { get; }
    public string FullName { get; }
    public Version? Version { get; }
    public string? CultureName { get; }
    public AssemblyNameFlags Flags { get; }
    public ImmutableArray<byte> PublicKeyOrToken { get; }
    
    public AssemblyName ToAssemblyName();
    
    public static AssemblyNameInfo Parse(ReadOnlySpan<char> assemblyName);
    public static bool TryParse(ReadOnlySpan<char> assemblyName, [NotNullWhenAttribute(true)] out AssemblyNameInfo? result);
}

The approved TypeName API needs following changes:

public sealed partial class TypeName : IEquatable<TypeName>
{
-    public string AssemblySimpleName { get; }
-    public System.Reflection.AssemblyName? GetAssemblyName();
+    public AssemblyNameInfo? AssemblyName { get; }
}

Usage Examples

Building high-level, opinionated parser on top of the low-level API:

AssemblyName GetAssemblyName(string unsafeInput)
{
    if (!AssemblyNameInfo.TryParse(unsafeInput, out AssemblyNameInfo info))
    {
        throw new ArgumentException("Invalid name!");
    }

    if (info.Name.AsSpan().IndexOfAny(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) >= 0)
    {
        throw new InvalidOperationException("AssemblyName must not contain path characters.");
    }

    // the following line throws CultureNotFoundException for non-predefined cultures
    _ = CultureInfo.GetCultureInfo(info.CultureName, predefinedOnly: true);

    return info.ToAssemblyName();
}

Alternative Designs

The proposed design has one property PublickKeyOrToken that can express the public key or its token. It's a design choice inherited from AssemblyName that uses AssemblyNameFlags.PublicKey flag to express what given byte array is.

We could have two dedicated properties and ctor arguments to express that: PublicKey and PublicKeyToken.

Risks

Providing low quality design may require introducing another AssemblyName-like type in the future.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions