-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
[API Proposal]: System.Runtime.CompilerServices.MetadataUpdateOriginalTypeAttribute #66222
Comments
I couldn't figure out the best area label to add to this issue. If you have write-permissions please help me learn by adding exactly one area label. |
@captainsafia FYI, since it's treading the same waters as dotnet/roslyn#55651 But that proposal is about the "original name" of other constructs that Roslyn mangles even in the baseline version of an assembly. Whereas this is about names that are mangled specifically as part of C# Hot Reload on classes that compile in an unsurprising way in the baseline assembly. |
Quite similar indeed! It would be great if we can get a two-for-one solution with this one but I recognize that it might be easier to solve the hot-reload specific problem. |
Tagging subscribers to this area: @tommcdon Issue DetailsBackground and motivationIn .NET 6 we added Additionally the The question arises, how should a framework relate the new types to the old types? or How do frameworks retrieve the original name of the type given only the (mangled) name of the new type that Roslyn generated in the delta? In ASP.NET Core, Razor pages are tagged with In other frameworks, such as Comet (an MVU framework atop .NET MAUI) every UI component including user code inherits from a base class that is marked with This API proposal introduces a new attribute that Roslyn will emit on updated API Proposalnamespace System.Runtime.CompilerServices
/// Types are marked with this attribute by C# Hot Reload to indicate the original name of a type that has been created by applying hot reload changes in a running application. It is not meant to be used directly by application developers.
[AttributeUsage(System.AttributeTargets.Class, AllowMultiple=false)]
public class MetadataUpdateOriginalNameAttribute : Attribute
{
/// The fullName parameter is the fully qualified name of the original type, including its namespace but not its assembly. Same as the Type.FullName property of the original type.
public MetadataUpdateOriginalNameAttribute(string fullName);
}
} API UsageGiven this pair of classes class [CreateNewOnMetadataUpdate]
public class BaseClass {}
namespace ABC {
public class DerivedClass : BaseClass {}
} A subsequent edit public class DerivedClass : BaseClass {
public int X {get; set;}
} will cause roslyn to emit a hot reload delta containing: namespace ABC {
[MetadataUpdateOriginalName("ABC.DerivedClass")]
public class DerivedClass#1 : BaseClass {
public int X {get; set;}
}
} A second edit public class DerivedClass : BaseClass {
public int X {get; set;}
public int Y {get; set;}
} will cause roslyn to emit a second hot reload delta containing: namespace ABC {
[MetadataUpdateOriginalName("ABC.DerivedClass")]
public class DerivedClass#2 : BaseClass {
public int X {get; set;}
public int Y {get; set;}
}
} Alternative Designs
RisksNo response
|
namespace System.Runtime.CompilerServices;
[AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Struct,
AllowMultiple=false, Inherited=false)]
public class MetadataUpdateOriginalTypeAttribute : Attribute
{
public MetadataUpdateOriginalTypeAttribute(Type originalType);
public Type OriginalType { get; }
} |
@Clancey any difference between pointing to the root of the edits (ie the original type the user wrote) vs the previous version? what happens in Comet if an instance of a previous version is created after an update has been applied (ie: @tmat : Is it ok for roslyn to emit a |
Background and motivation
In .NET 6 we added
CreateNewOnMetadataUpdateAttribute
to allow frameworks to mark types that do not carry any state that needs to be preserved between hot reload updates (or that any relevant state can be migrated by the framework itself from old instances of old types to new instances of new types). When Roslyn generates a delta for a type with this attribute, more kinds of edits are allowed, and a new class is emitted with a mangled name, instead of a modification to the metadata of the original class.Additionally the
MetadataUpdateHandlerAttribute
allows frameworks to register callbacks that are invoked by the hot reload agent after an update is applied. The handlers receive a collection of the modified types. In the case ofCreateNewOnMetadataUpdate
types, it is the new types that are included in the collection.The question arises, how should a framework relate the new types to the old types? or How do frameworks retrieve the original name of the type given only the (mangled) name of the new type that Roslyn generated in the delta?
In ASP.NET Core,
.cshtml
pages are tagged with[CreateNewOnMetadataUpdate]
.In other frameworks, such as Comet, every UI component including user code inherits from a base class that is marked with
[CreateNewOnMetadataUpdate]
, and there is no convenient additional attribute to identify the previous and current versions of a type.This API proposal introduces a new attribute that Roslyn will emit on updated
[CreateNewOnMetadataUpdate]
types that will include their original name.API Proposal
API Usage
Given this pair of classes class
A subsequent edit
will cause roslyn to emit a hot reload delta containing:
A second edit
will cause roslyn to emit a second hot reload delta containing:
Alternative Designs
We could formalize the name mangling that Roslyn uses for the new types and expect framework authors to know how to parse them. (Or provide some API to do the de-mangling).
We could employ some metadata encoding scheme for the new types: Roslyn could emit the new types as nested types of the original type, for example. Then to find the relationship between the old and new type we would merely get the enclosing type.
A minor variation on the proposal above: Instead of each type carrying an attribute with its original name, instead the attribute could contain the name of the preceding most-recent type (e.g.
MetadataUpdateOriginalName("ABC.DerivedClass#1")
onDerivedClass#2
). This seems like a minor difference. Frameworks likely need to keep track of all previous edits in any case.We could go more general: extend the
CompilerGeneratred
attribute with anOriginalName
property as proposed inSupport retrieving original type name from mangled type name roslyn#55651 in order to provide a mechanism to reconstruct the original name of other compiler-generated constructs such as lambdas and nested function in addition to reloadable types.
Risks
No response
The text was updated successfully, but these errors were encountered: