Сценарии - Добавление ссылки после создания Activity 

Page / - Изменено Alexandr Fokin в 2022/12/07 07:48 

Добавление ссылки после создания Activity 
Изменено Alexandr Fokin
в 2022/12/07 07:48

Оглавление

Reflection | Рефлексия
Expression tree
runtime/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagLinkedList.cs
https://github.com/dotnet/runtime/blob/7bac4e8fa611eb02ac1bd27b97a8570cbf321437/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/DiagLinkedList.cs

public static class ActivityExtensions
{
   private static readonly Action<Activity, ActivityLink> ActivityAddLink1;
   private static readonly Action<Activity, ActivityLink> ActivityAddLink2;

   static ActivityExtensions() 
    {
       var activityType = typeof(Activity);
       var linkType = typeof(ActivityLink);
                   
       var linksField = activityType.GetField(
            name: "_links",
            bindingAttr:  BindingFlags.Instance | BindingFlags.NonPublic
            )!;

       var collectionType = linksField.FieldType;
       var collectionAddMethod = collectionType.GetMethod(
                name: "Add",
                bindingAttr: BindingFlags.Instance | BindingFlags.Public
            )!;

        {
           var constructorMethod = collectionType.GetConstructor(
                types: linkType.OneItemArray()
            )!;

            ActivityAddLink2 = (a, e) =>
            {
               var parameter = ((object)e).OneItemArray();
               var collection = linksField.GetValue(a);

               if (collection == null)
                {
                    collection = constructorMethod.Invoke(parameter);
                    linksField.SetValue(a, collection);
                }
               else
                {
                    collectionAddMethod.Invoke(
                        collection,
                        parameter
                    );
                }
            };
        }

        {
           var constructorMethod = collectionType.GetConstructor(
                types: linkType.OneItemArray()
            )!;

           var activityParameter = Expression.Parameter(activityType);
           var linkParameter = Expression.Parameter(linkType);

           var collectionExp = Expression.Field(activityParameter, linksField);

           var addExp = Expression.Call(collectionExp, collectionAddMethod, linkParameter);

           var constructorExp = Expression.New(constructorMethod, linkParameter);
           var constructorAndSetExp = Expression.Assign(collectionExp, constructorExp);

           var addMethodLambda = Expression.Lambda<Action<Activity, ActivityLink>>(                        
                body: addExp,                        
                parameters: new ParameterExpression[] { activityParameter, linkParameter }                        
                );
           var createCollectionMethodLambda = Expression.Lambda<Action<Activity, ActivityLink>>(                       
                body: constructorAndSetExp,                        
                parameters: new ParameterExpression[] { activityParameter, linkParameter }                        
                );

            Action<Activity, ActivityLink> addMethod = addMethodLambda.Compile();
            Action<Activity, ActivityLink> createCollectionMethod = createCollectionMethodLambda.Compile();               

            ActivityAddLink1 = (a, e) =>
            {
               if (a.Links.Any())
                {
                    addMethod(a, e);                        
                }
               else 
                {
                    createCollectionMethod(a, e);
                }
            };
        }
    }

    [Obsolete]
   public static void AddLink(
       this Activity activity,
       in ActivityLink link
        )
    {
        ActivityAddLink1(
            activity,
            link
            );
    }

   public static void AddLink(
       this Activity activity,
        Activity linkActivity,
       params (string Key, string Value)[] tags
        )
    {
       var link = new ActivityLink(
            linkActivity.Context,
           new ActivityTagsCollection(
                tags.Select(
                    e => new KeyValuePair<string, object?>(e.Key, e.Value)
                    )
                )
            );

        AddLink(
            activity,
            link
            );
    }
}