Добавление ссылки после создания Activity
Редактировал(а) Alexandr Fokin 2022/12/07 07:48
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
);
}
}
{
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
);
}
}