Location>code7788 >text

NET Static Code Weaving - Meat Loaf (Rougamo) 4.0

Popularity:516 ℃/2024-08-12 08:11:56

Meat Loaf (/inversionhourglass/Rougamo), a compile-time AOP component. Compared to dynamic proxy AOP needs to be initialized at application startup , compile-time completion of the code weaving meat loafers reduce the application startup initialization time , while meat loafers also support all kinds of methods , whether the method is synchronous or asynchronous , static or instance , constructor or property are supported . Meat Loaf does not need to be initialized , write a good cut type can be applied directly to the corresponding method , while Meat Loaf also provides a method feature matching and class AspectJ expression matching batch application rules .

asynchronous cutout

Thanks to the changes made in 3.0 to the way facets are implemented, version 4.0 implements an asynchronous facet feature based on proxy weaving. What are asynchronous facets? To put it bluntly, it's a newOnEntry/OnSuccess/OnException/OnExitCorresponding asynchronous methodsOnEntryAsync/OnSuccessAsync/OnExceptionAsync/OnExitAsync

How to use

To write an asynchronous cutover, you generally inherit theAsyncMoAttributemaybeAsyncMoand then rewrite theOnXxxAsyncMethods will suffice.

// Defining cutout types
public class TestAttribute : AsyncMoAttribute
{
    public override async ValueTask OnEntryAsync(MethodContext) { }
    
    public override async ValueTask OnSuccessAsync(MethodContext) { }
    
    public override async ValueTask OnExceptionAsync(MethodContext) { }
    
    public override async ValueTask OnExitAsync(MethodContext) { }
}

public class Cls
{
    // Applying to synchronization methods
    [Test]
    public void M() { }

    // Applying to asynchronous methods
    [Test]
    public static async Task MAsync() => ();
}

Talk about details.

After understanding how asynchronous facets are used you may have a question: what does a synchronous facet look like on an asynchronous method and what does an asynchronous facet look like on a synchronous method? Before answering this question, let's take a look at the followingAsyncMoAttributeThe source code for the

public abstract class AsyncMoAttribute : RawMoAttribute
{
    public override ValueTask OnEntryAsync(MethodContext context) => default;

    public override ValueTask OnExceptionAsync(MethodContext context) => default;

    public override ValueTask OnSuccessAsync(MethodContext context) => default;

    public override ValueTask OnExitAsync(MethodContext context) => default;

    public sealed override void OnEntry(MethodContext context)
    {
        OnEntryAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnException(MethodContext context)
    {
        OnExceptionAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnSuccess(MethodContext context)
    {
        OnSuccessAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }

    public sealed override void OnExit(MethodContext context)
    {
        OnExitAsync(context).ConfigureAwait(false).GetAwaiter().GetResult();
    }
}

As you can see from the source code, theAsyncMoAttributeis the one that contains the synchronous facet methods, along with the default implementation, which implements the code by calling the asynchronous facet methods directly and thenGetResult. Again, if you go to theMoAttributesource code, you will see that theMoAttributeIt also has asynchronous facet methods, and the default implementation is to call synchronous facet methods. So, the answer to the question above is that the synchronous facet methods will be called in the synchronous methods and the asynchronous facet methods will be called in the asynchronous methods.

At this point you may have another question: since theAsyncMoAttributecap (a poem)MoAttributeWhat's the point of having two classes when you have all the synchronous and asynchronous facet methods?

This is a design that combines convenience and security considerations. As mentioned earlier, Meatpacking will call synchronous cutout methods in synchronous methods and asynchronous cutout methods in asynchronous methods. If you don't separate the two classes and continue to useMoAttributeThen first a question:MoAttributeShould all the faceted methods in should be designed as abstract methods for subclasses to implement all synchronous asynchronous faceted methods, or should they be designed as dummy methods with default implementations for subclasses to rewrite the methods as they choose?

  • Choosing to design as an abstract method
    Designing it as an abstract method adds extra work for subclasses to implement all the faceted methods at inheritance time.

  • Choose to design as a dummy method with a default implementation
    Choosing this approach brings up another question: whether the default implementation uses an empty method implementation, or whether it uses an inter-call between asynchronous and synchronous facets (calling synchronous facet methods by default in asynchronous facet methods, and calling asynchronous facet methods by default in synchronous facet methods)

    • Realized using the null method
      Since it is a virtual method, subclasses inherit theMoAttributeIt is not mandatory to override the virtual methods, so if you override a synchronous facet method but do not override the corresponding asynchronous facet method, it will result in the facet type behaving differently when applied to synchronous methods than to asynchronous methods, which is often not what is expected.
    • Using inter-calls between asynchronous and synchronous facets
      The same problem exists as with an empty method implementation, but with more serious consequences. For example, if you inherit theMoAttributeSince you don't need to do anything when the method exits, you neither override theOnExitNor did it rewrite theOnExitAsyncthen the method exits with a call toOnExitmaybeOnExitAsyncIt will appear when theOnExitcap (a poem)OnExitAsyncRecursive call.

From the above illustration, you should be able to understand the reason for dividing synchronous and asynchronous facets into two types. If you are observant and careful, you may have noticed that the aboveAsyncMoAttributeThe synchronized cutout methods in the source code also add thesealedkeyword, this is also to increase the security, prohibit rewriting, to avoid the rewrite method due to the IDE intelligent prompts to rewrite the synchronous cutout method but not rewrite the corresponding asynchronous method, resulting in synchronous cutout method and asynchronous cutout method performance inconsistency problems.

Fully customizable RawMoAttribute

this being the caseMoAttributecap (a poem)AsyncMoAttributeThe default implementation is to call the corresponding method directly, so what if I don't think the default implementation is optimal, for exampleAsyncMoAttributeThe default synchronization cutout is to call the asynchronous cutout directly and then wait for the synchronization to complete, I have a better synchronization solution, how should I do it, after all, the synchronization cutout methods all pass thesealedKeywords are forbidden to be rewritten.

Careful you're checking aboveAsyncMoAttributeAs may have been discovered at the time of the source code, theAsyncMoAttributeinherited fromRawMoAttributeequalMoAttributeAlso inherited fromRawMoAttributeRawMoAttributeOpens up all the synchronous asynchronous cutout methods, which are abstract methods that allow you to fully customize the synchronous asynchronous cutout. After inheriting theRawMoAttributeWhen implementing synchronous asynchronous facet methods you need to pay attention to the previously mentioned: avoid differences in code logic between synchronous and asynchronous facets, and avoid recursive calls between synchronous and asynchronous facet methods.

Other updates

New Type

In addition to the above mentionedAsyncMoAttributecap (a poem)RawMoAttributeThe newest addition to the list is theRawMO,MO,AsyncMoRespectively, withRawMoAttribute,MoAttribute,AsyncMoAttributecounterpart, the difference being that the latter inherits fromAttribute. This is because meatloaf can be applied in a way other than Attribute applications by theImplementing the empty interface IRougamo is applied in a way that does not require the type to be an Attribute subclass, and of course Attribute subclasses are accepted, the option of not inheriting Attribute is just provided here.

Forced Synchronization for Performance Optimization

In the introduction to asynchronous facets it was stated that synchronous methods will call synchronous facets and asynchronous methods will call asynchronous facets. This setting is a good one by default, but if your faceted operations don't involve asynchronous operations at all, you don't actually need to call asynchronous facets in asynchronous methods, because asynchronous facets walk a layer ofValueTaskpackaging, there would be additional overhead compared to synchronized cuts. In this case, it is possible to pass theForceSyncattribute is set in an asynchronous method that needs to enforce a synchronous cutout:

public class TestAttribute : MoAttribute
{
    // In asynchronous methods, OnEntry and OnExit will force the synchronous facet methods to be called.
    public override ForceSync ForceSync => | ;
}

In fact, if the performance requirements are not so strict, it is possible not to set theForceSyncthat the meat loaf has been adoptedValueTask, the default asynchronous facet methods have very limited additional overhead for wrapping synchronous facet methods.

Special note on async void

As we talked about when 3.0 was released, the proxy weaving approach used since 3.0 has been very useful for theasync voidThe support may not work the way you expect. For details, please jump to see theasync void special note

caterasync voidis not a recommended use (It's not officially recommended either.), so the decision was not rightasync voidDo more adaptation work and continue to follow the 3.0 approach of putting theasync voidmethod as if it were an ordinaryvoidThe return value is viewed as a synchronized method. However, unlike 3.0, in version 4.0 if you find that theasync voidMethods with the meatloaf cutout type applied to them will generate an MSBuild alert at compile time. Alert messages are often not easy to notice if you are sure you don't want theasync voidIf you want to apply the meat loaf cutout type, or if you want to be alerted when this occurs so that you can make the appropriate changes, then you can add thePropertyGroupAdd a new child node under the node<FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>This configuration will change the warning message generated by Fody to an error message, thus making the compilation fail for the purpose of alerting.

<Project Sdk="">
  <PropertyGroup>
    <FodyTreatWarningsAsErrors>true</FodyTreatWarningsAsErrors>
  </PropertyGroup>
</Project>

MethodContext member changes

removingMethodContexthit the nail on the headIsAsync, IsIterator, MosNonEntryFIFO, Dataattribute, which sets theRealReturnTypeMarked as obsolete and hidden, with a newTaskReturnTypeattribute, which is the same as theRealReturnTypehas a similar function.

Configuration file smart tips

Meatpacking has some license configuration items that can be found in thein the configuration, seeconfiguration item. Now add the corresponding xml schema for these configurations, after modifying the(used form a nominal expression)RougamoA smart tip will appear when the node.