namespace System.Diagnostics
{
- public partial class DiagnosticListener : System.Diagnostics.DiagnosticSource, System.IDisposable, System.IObservable<System.Collections.Generic.KeyValuePair<string, object>>
+ public partial class DiagnosticListener : System.Diagnostics.DiagnosticSource, System.IDisposable, System.IObservable<System.Collections.Generic.KeyValuePair<string, object?>>
{
public DiagnosticListener(string name) { }
public static System.IObservable<System.Diagnostics.DiagnosticListener> AllListeners { get { throw null; } }
public virtual void Dispose() { }
public bool IsEnabled() { throw null; }
public override bool IsEnabled(string name) { throw null; }
- public override bool IsEnabled(string name, object arg1, object arg2 = null) { throw null; }
- public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object>> observer) { throw null; }
- public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object>> observer, System.Func<string, object, object, bool> isEnabled) { throw null; }
- public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object>> observer, System.Predicate<string> isEnabled) { throw null; }
+ public override bool IsEnabled(string name, object? arg1, object? arg2 = null) { throw null; }
+ public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object?>> observer) { throw null; }
+ public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object?>> observer, System.Func<string, object?, object?, bool>? isEnabled) { throw null; }
+ public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object?>> observer, System.Predicate<string>? isEnabled) { throw null; }
public override string ToString() { throw null; }
- public override void Write(string name, object value) { }
+ public override void Write(string name, object? value) { }
}
public abstract partial class DiagnosticSource
{
protected DiagnosticSource() { }
public abstract bool IsEnabled(string name);
- public virtual bool IsEnabled(string name, object arg1, object arg2 = null) { throw null; }
- public abstract void Write(string name, object value);
+ public virtual bool IsEnabled(string name, object? arg1, object? arg2 = null) { throw null; }
+ public abstract void Write(string name, object? value);
}
}
<PropertyGroup>
<Configurations>net45-Debug;net45-Release;netfx-Debug;netfx-Release;netstandard-Debug;netstandard-Release;netstandard1.1-Debug;netstandard1.1-Release;netstandard1.3-Debug;netstandard1.3-Release</Configurations>
<CLSCompliant>false</CLSCompliant>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetGroup)' == 'net45' OR '$(TargetGroup)' == 'netfx'">
<DefineConstants>$(DefineConstants);ALLOW_PARTIALLY_TRUSTED_CALLERS</DefineConstants>
{
public Activity(string operationName) { }
public System.Diagnostics.ActivityTraceFlags ActivityTraceFlags { get { throw null; } set { } }
- public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> Baggage { get { throw null; } }
- public static System.Diagnostics.Activity Current
+ public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string?>> Baggage { get { throw null; } }
+ public static System.Diagnostics.Activity? Current
{
#if ALLOW_PARTIALLY_TRUSTED_CALLERS
[System.Security.SecuritySafeCriticalAttribute]
public static System.Diagnostics.ActivityIdFormat DefaultIdFormat { get { throw null; } set { } }
public System.TimeSpan Duration { get { throw null; } }
public static bool ForceDefaultIdFormat { get { throw null; } set { } }
- public string Id
+ public string? Id
{
#if ALLOW_PARTIALLY_TRUSTED_CALLERS
[System.Security.SecuritySafeCriticalAttribute]
}
public System.Diagnostics.ActivityIdFormat IdFormat { get { throw null; } }
public string OperationName { get { throw null; } }
- public System.Diagnostics.Activity Parent { get { throw null; } }
- public string ParentId { get { throw null; } }
+ public System.Diagnostics.Activity? Parent { get { throw null; } }
+ public string? ParentId { get { throw null; } }
public System.Diagnostics.ActivitySpanId ParentSpanId { get { throw null; } }
public bool Recorded { get { throw null; } }
- public string RootId { get { throw null; } }
+ public string? RootId { get { throw null; } }
public System.Diagnostics.ActivitySpanId SpanId { get { throw null; } }
public System.DateTime StartTimeUtc { get { throw null; } }
- public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string>> Tags { get { throw null; } }
+ public System.Collections.Generic.IEnumerable<System.Collections.Generic.KeyValuePair<string, string?>> Tags { get { throw null; } }
public System.Diagnostics.ActivityTraceId TraceId { get { throw null; } }
- public string TraceStateString { get { throw null; } set { } }
- public System.Diagnostics.Activity AddBaggage(string key, string value) { throw null; }
- public System.Diagnostics.Activity AddTag(string key, string value) { throw null; }
- public string GetBaggageItem(string key) { throw null; }
+ public string? TraceStateString { get { throw null; } set { } }
+ public System.Diagnostics.Activity AddBaggage(string key, string? value) { throw null; }
+ public System.Diagnostics.Activity AddTag(string key, string? value) { throw null; }
+ public string? GetBaggageItem(string key) { throw null; }
public System.Diagnostics.Activity SetEndTime(System.DateTime endTimeUtc) { throw null; }
public System.Diagnostics.Activity SetIdFormat(System.Diagnostics.ActivityIdFormat format) { throw null; }
public System.Diagnostics.Activity SetParentId(System.Diagnostics.ActivityTraceId traceId, System.Diagnostics.ActivitySpanId spanId, System.Diagnostics.ActivityTraceFlags activityTraceFlags = System.Diagnostics.ActivityTraceFlags.None) { throw null; }
public static System.Diagnostics.ActivitySpanId CreateFromUtf8String(System.ReadOnlySpan<byte> idData) { throw null; }
public static System.Diagnostics.ActivitySpanId CreateRandom() { throw null; }
public bool Equals(System.Diagnostics.ActivitySpanId spanId) { throw null; }
- public override bool Equals(object obj) { throw null; }
+ public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(System.Diagnostics.ActivitySpanId spanId1, System.Diagnostics.ActivitySpanId spandId2) { throw null; }
public static bool operator !=(System.Diagnostics.ActivitySpanId spanId1, System.Diagnostics.ActivitySpanId spandId2) { throw null; }
public static System.Diagnostics.ActivityTraceId CreateFromUtf8String(System.ReadOnlySpan<byte> idData) { throw null; }
public static System.Diagnostics.ActivityTraceId CreateRandom() { throw null; }
public bool Equals(System.Diagnostics.ActivityTraceId traceId) { throw null; }
- public override bool Equals(object obj) { throw null; }
+ public override bool Equals(object? obj) { throw null; }
public override int GetHashCode() { throw null; }
public static bool operator ==(System.Diagnostics.ActivityTraceId traceId1, System.Diagnostics.ActivityTraceId traceId2) { throw null; }
public static bool operator !=(System.Diagnostics.ActivityTraceId traceId1, System.Diagnostics.ActivityTraceId traceId2) { throw null; }
}
public partial class DiagnosticListener
{
- public override void OnActivityExport(System.Diagnostics.Activity activity, object payload) { }
- public override void OnActivityImport(System.Diagnostics.Activity activity, object payload) { }
- public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object>> observer, System.Func<string, object, object, bool> isEnabled, System.Action<System.Diagnostics.Activity, object> onActivityImport = null, System.Action<System.Diagnostics.Activity, object> onActivityExport = null) { throw null; }
+ public override void OnActivityExport(System.Diagnostics.Activity activity, object? payload) { }
+ public override void OnActivityImport(System.Diagnostics.Activity activity, object? payload) { }
+ public virtual System.IDisposable Subscribe(System.IObserver<System.Collections.Generic.KeyValuePair<string, object?>> observer, System.Func<string, object?, object?, bool>? isEnabled, System.Action<System.Diagnostics.Activity, object?>? onActivityImport = null, System.Action<System.Diagnostics.Activity, object?>? onActivityExport = null) { throw null; }
}
public abstract partial class DiagnosticSource
{
- public virtual void OnActivityExport(System.Diagnostics.Activity activity, object payload) { }
- public virtual void OnActivityImport(System.Diagnostics.Activity activity, object payload) { }
- public System.Diagnostics.Activity StartActivity(System.Diagnostics.Activity activity, object args) { throw null; }
- public void StopActivity(System.Diagnostics.Activity activity, object args) { }
+ public virtual void OnActivityExport(System.Diagnostics.Activity activity, object? payload) { }
+ public virtual void OnActivityImport(System.Diagnostics.Activity activity, object? payload) { }
+ public System.Diagnostics.Activity StartActivity(System.Diagnostics.Activity activity, object? args) { throw null; }
+ public void StopActivity(System.Diagnostics.Activity activity, object? args) { }
}
}
<CLSCompliant>false</CLSCompliant>
<NoWarn>$(NoWarn);SA1205</NoWarn>
<Configurations>net45-Debug;net45-Release;net46-Debug;net46-Release;netcoreapp-Debug;netcoreapp-Release;netfx-Debug;netfx-Release;netstandard-Debug;netstandard-Release;netstandard1.1-Debug;netstandard1.1-Release;netstandard1.3-Debug;netstandard1.3-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
+ <Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetGroup)' == 'netstandard1.1' OR '$(TargetGroup)' == 'net45'">
<DefineConstants>$(DefineConstants);NO_EVENTSOURCE_COMPLEX_TYPE_SUPPORT</DefineConstants>
{
public partial class Activity
{
- private static readonly AsyncLocal<Activity> s_current = new AsyncLocal<Activity>();
+ private static readonly AsyncLocal<Activity?> s_current = new AsyncLocal<Activity?>();
/// <summary>
/// Gets or sets the current operation (Activity) for the current thread. This flows
/// across async calls.
/// </summary>
- public static Activity Current
+ public static Activity? Current
{
get { return s_current.Value; }
set
}
}
- private static void SetCurrent(Activity activity)
+ private static void SetCurrent(Activity? activity)
{
s_current.Value = activity;
}
public partial class Activity
{
#pragma warning disable CA1825 // Array.Empty<T>() doesn't exist in all configurations
- private static readonly IEnumerable<KeyValuePair<string, string>> s_emptyBaggageTags = new KeyValuePair<string, string>[0];
+ private static readonly IEnumerable<KeyValuePair<string, string?>> s_emptyBaggageTags = new KeyValuePair<string, string?>[0];
#pragma warning restore CA1825
private const byte ActivityTraceFlagsIsSet = 0b_1_0000000; // Internal flag to indicate if flags have been set
/// </summary>
public static bool ForceDefaultIdFormat { get; set; }
- private string _traceState;
+ private string? _traceState;
private State _state;
private int _currentChildId; // A unique number for all children of this activity.
// State associated with ID.
- private string _id;
- private string _rootId;
+ private string? _id;
+ private string? _rootId;
// State associated with ParentId.
- private string _parentId;
+ private string? _parentId;
// W3C formats
- private string _parentSpanId;
- private string _traceId;
- private string _spanId;
+ private string? _parentSpanId;
+ private string? _traceId;
+ private string? _spanId;
private byte _w3CIdFlags;
- private KeyValueListNode _tags;
- private KeyValueListNode _baggage;
+ private KeyValueListNode? _tags;
+ private KeyValueListNode? _baggage;
/// <summary>
/// An operation name is a COARSEST name that is useful grouping/filtering.
/// reasonable, but arguments (e.g. specific accounts etc), should not be in
/// the name but rather in the tags.
/// </summary>
- public string OperationName { get; }
+ public string OperationName { get; } = null!;
/// <summary>
/// If the Activity that created this activity is from the same process you can get
/// parent (a root activity) or if the Parent is from outside the process.
/// </summary>
/// <seealso cref="ParentId"/>
- public Activity Parent { get; private set; }
+ public Activity? Parent { get; private set; }
/// <summary>
/// If the Activity has ended (<see cref="Stop"/> or <see cref="SetEndTime"/> was called) then this is the delta
/// - '|a000b421-5d183ab6.1.8e2d4c28_' - Id of the grand child activity. It was started in another process and ends with '_'<para />
/// 'a000b421-5d183ab6' is a <see cref="RootId"/> for the first Activity and all its children
/// </example>
- public string Id
+ public string? Id
{
#if ALLOW_PARTIALLY_TRUSTED_CALLERS
[System.Security.SecuritySafeCriticalAttribute]
/// <para/>
/// See <see href="https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/ActivityUserGuide.md#id-format"/> for more details
/// </summary>
- public string ParentId
+ public string? ParentId
{
get
{
/// RootId may be null if Activity has neither ParentId nor Id.
/// See <see href="https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/ActivityUserGuide.md#id-format"/> for more details
/// </summary>
- public string RootId
+ public string? RootId
{
get
{
//Presumably, it will be called by logging systems for every log record, so we cache it.
if (_rootId == null)
{
- string rootId = null;
+ string? rootId = null;
if (Id != null)
{
rootId = GetRootId(Id);
/// however is NOT passed on to the children of this activity.
/// </summary>
/// <seealso cref="Baggage"/>
- public IEnumerable<KeyValuePair<string, string>> Tags
+ public IEnumerable<KeyValuePair<string, string?>> Tags
{
get
{
- KeyValueListNode tags = _tags;
+ KeyValueListNode? tags = _tags;
return tags != null ?
Iterate(tags) :
s_emptyBaggageTags;
- static IEnumerable<KeyValuePair<string, string>> Iterate(KeyValueListNode tags)
+ static IEnumerable<KeyValuePair<string, string?>> Iterate(KeyValueListNode? tags)
{
do
{
- yield return tags.keyValue;
+ yield return tags!.keyValue;
tags = tags.Next;
}
while (tags != null);
/// In general, if you are not using the data at runtime, you should be using Tags
/// instead.
/// </summary>
- public IEnumerable<KeyValuePair<string, string>> Baggage
+ public IEnumerable<KeyValuePair<string, string?>> Baggage
{
get
{
- for (Activity activity = this; activity != null; activity = activity.Parent)
+ for (Activity? activity = this; activity != null; activity = activity.Parent)
{
if (activity._baggage != null)
{
return s_emptyBaggageTags;
- static IEnumerable<KeyValuePair<string, string>> Iterate(Activity activity)
+ static IEnumerable<KeyValuePair<string, string?>> Iterate(Activity? activity)
{
+ Debug.Assert(activity != null);
do
{
- for (KeyValueListNode baggage = activity._baggage; baggage != null; baggage = baggage.Next)
+ for (KeyValueListNode? baggage = activity._baggage; baggage != null; baggage = baggage.Next)
{
yield return baggage.keyValue;
}
/// Returns the value of the key-value pair added to the activity with <see cref="AddBaggage(string, string)"/>.
/// Returns null if that key does not exist.
/// </summary>
- public string GetBaggageItem(string key)
+ public string? GetBaggageItem(string key)
{
- foreach (KeyValuePair<string, string> keyValue in Baggage)
+ foreach (KeyValuePair<string, string?> keyValue in Baggage)
if (key == keyValue.Key)
return keyValue.Value;
return null;
/// is useful to log but not needed for runtime control (for the latter, <see cref="Baggage"/>)
/// </summary>
/// <returns>'this' for convenient chaining</returns>
- public Activity AddTag(string key, string value)
+ public Activity AddTag(string key, string? value)
{
- KeyValueListNode currentTags = _tags;
- KeyValueListNode newTags = new KeyValueListNode() { keyValue = new KeyValuePair<string, string>(key, value) };
+ KeyValueListNode? currentTags = _tags;
+ KeyValueListNode newTags = new KeyValueListNode() { keyValue = new KeyValuePair<string, string?>(key, value) };
do
{
newTags.Next = currentTags;
/// Returns 'this' for convenient chaining.
/// </summary>
/// <returns>'this' for convenient chaining</returns>
- public Activity AddBaggage(string key, string value)
+ public Activity AddBaggage(string key, string? value)
{
- KeyValueListNode currentBaggage = _baggage;
- KeyValueListNode newBaggage = new KeyValueListNode() { keyValue = new KeyValuePair<string, string>(key, value) };
+ KeyValueListNode? currentBaggage = _baggage;
+ KeyValueListNode newBaggage = new KeyValueListNode() { keyValue = new KeyValuePair<string, string?>(key, value) };
do
{
{
if (_parentId == null && _parentSpanId is null)
{
- Activity parent = Current;
+ Activity? parent = Current;
if (parent != null)
{
// The parent change should not form a loop. We are actually guaranteed this because
/// it is expected to be special cased (it has its own HTTP header), it is more
/// convenient/efficient if it is not lumped in with other baggage.
/// </summary>
- public string TraceStateString
+ public string? TraceStateString
{
get
{
- for (Activity activity = this; activity != null; activity = activity.Parent)
+ for (Activity? activity = this; activity != null; activity = activity.Parent)
{
- string val = activity._traceState;
+ string? val = activity._traceState;
if (val != null)
return val;
}
{
if (_parentSpanId is null)
{
- string parentSpanId = null;
+ string? parentSpanId = null;
if (_parentId != null && IsW3CId(_parentId))
{
try
return *((long*)&g);
}
- private static bool ValidateSetCurrent(Activity activity)
+ private static bool ValidateSetCurrent(Activity? activity)
{
bool canSet = activity == null || (activity.Id != null && !activity.IsFinished);
if (!canSet)
/// </summary>
private partial class KeyValueListNode
{
- public KeyValuePair<string, string> keyValue;
- public KeyValueListNode Next;
+ public KeyValuePair<string, string?> keyValue;
+ public KeyValueListNode? Next;
}
[Flags]
#endif
public readonly struct ActivityTraceId : IEquatable<ActivityTraceId>
{
- private readonly string _hexString;
+ private readonly string? _hexString;
- internal ActivityTraceId(string hexString) => _hexString = hexString;
+ internal ActivityTraceId(string? hexString) => _hexString = hexString;
/// <summary>
/// Create a new TraceId with at random number in it (very likely to be unique)
{
return _hexString == traceId._hexString;
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
if (obj is ActivityTraceId traceId)
return _hexString == traceId._hexString;
#endif
public readonly struct ActivitySpanId : IEquatable<ActivitySpanId>
{
- private readonly string _hexString;
+ private readonly string? _hexString;
- internal ActivitySpanId(string hexString) => _hexString = hexString;
+ internal ActivitySpanId(string? hexString) => _hexString = hexString;
/// <summary>
/// Create a new SpanId with at random number in it (very likely to be unique)
{
return _hexString == spanId._hexString;
}
- public override bool Equals(object obj)
+ public override bool Equals(object? obj)
{
- if (!(obj is ActivitySpanId))
- {
- return false;
- }
-
- ActivitySpanId spanId = (ActivitySpanId)obj;
- return _hexString == spanId._hexString;
+ if (obj is ActivitySpanId spanId)
+ return _hexString == spanId._hexString;
+ return false;
}
public override int GetHashCode()
{
/// https://github.com/dotnet/corefx/blob/master/src/System.Diagnostics.DiagnosticSource/src/DiagnosticSourceUsersGuide.md
/// for instructions on its use.
/// </summary>
- public partial class DiagnosticListener : DiagnosticSource, IObservable<KeyValuePair<string, object>>, IDisposable
+ public partial class DiagnosticListener : DiagnosticSource, IObservable<KeyValuePair<string, object?>>, IDisposable
{
/// <summary>
/// When you subscribe to this you get callbacks for all NotificationListeners in the appdomain
///
/// If this parameter is null, no filtering is done (all overloads of DiagnosticSource.IsEnabled return true).
/// </param>
- public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Predicate<string> isEnabled)
+ public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object?>> observer, Predicate<string>? isEnabled)
{
IDisposable subscription;
if (isEnabled == null)
///
/// If this parameter is null, no filtering is done (all overloads of DiagnosticSource.IsEnabled return true).
/// </param>
- public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Func<string, object, object, bool> isEnabled)
+ public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object?>> observer, Func<string, object?, object?, bool>? isEnabled)
{
return isEnabled == null ?
SubscribeInternal(observer, null, null, null, null) :
/// <summary>
/// Same as other Subscribe overload where the predicate is assumed to always return true.
/// </summary>
- public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer)
+ public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object?>> observer)
{
return SubscribeInternal(observer, null, null, null, null);
}
}
// Indicate completion to all subscribers.
- DiagnosticSubscription subscriber = null;
+ DiagnosticSubscription? subscriber = null;
Interlocked.Exchange(ref subscriber, _subscriptions);
while (subscriber != null)
{
/// <returns></returns>
public override string ToString()
{
- return Name;
+ return Name ?? string.Empty;
}
#region private
/// </summary>
public override bool IsEnabled(string name)
{
- for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
+ for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
{
if (curSubscription.IsEnabled1Arg == null || curSubscription.IsEnabled1Arg(name))
return true;
/// <summary>
/// Override abstract method
/// </summary>
- public override bool IsEnabled(string name, object arg1, object arg2 = null)
+ public override bool IsEnabled(string name, object? arg1, object? arg2 = null)
{
- for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
+ for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
{
if (curSubscription.IsEnabled3Arg == null || curSubscription.IsEnabled3Arg(name, arg1, arg2))
return true;
/// <summary>
/// Override abstract method
/// </summary>
- public override void Write(string name, object value)
+ public override void Write(string name, object? value)
{
- for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
- curSubscription.Observer.OnNext(new KeyValuePair<string, object>(name, value));
+ for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
+ curSubscription.Observer.OnNext(new KeyValuePair<string, object?>(name, value));
}
/// <summary>
// Note that Subscriptions are READ ONLY. This means you never update any fields (even on removal!)
private class DiagnosticSubscription : IDisposable
{
- internal IObserver<KeyValuePair<string, object>> Observer;
+ internal IObserver<KeyValuePair<string, object?>> Observer = null!;
// IsEnabled1Arg and IsEnabled3Arg represent IsEnabled callbacks.
// - IsEnabled1Arg invoked for DiagnosticSource.IsEnabled(string)
// IsEnabled1Arg falls back to IsEnabled3Arg with null context
// Thus, dispatching is very efficient when producer and consumer agree on number of IsEnabled arguments
// Argument number mismatch between producer/consumer adds extra cost of adding or omitting context parameters
- internal Predicate<string> IsEnabled1Arg;
- internal Func<string, object, object, bool> IsEnabled3Arg;
- internal Action<Activity, object> OnActivityImport;
- internal Action<Activity, object> OnActivityExport;
+ internal Predicate<string>? IsEnabled1Arg;
+ internal Func<string, object?, object?, bool>? IsEnabled3Arg;
+ internal Action<Activity, object?>? OnActivityImport;
+ internal Action<Activity, object?>? OnActivityExport;
- internal DiagnosticListener Owner; // The DiagnosticListener this is a subscription for.
- internal DiagnosticSubscription Next; // Linked list of subscribers
+ internal DiagnosticListener Owner = null!; // The DiagnosticListener this is a subscription for.
+ internal DiagnosticSubscription? Next; // Linked list of subscribers
public void Dispose()
{
// TO keep this lock free and easy to analyze, the linked list is READ ONLY. Thus we copy
while (true)
{
- DiagnosticSubscription subscriptions = Owner._subscriptions;
- DiagnosticSubscription newSubscriptions = Remove(subscriptions, this); // Make a new list, with myself removed.
+ DiagnosticSubscription? subscriptions = Owner._subscriptions;
+ DiagnosticSubscription? newSubscriptions = Remove(subscriptions, this); // Make a new list, with myself removed.
// try to update, but if someone beat us to it, then retry.
if (Interlocked.CompareExchange(ref Owner._subscriptions, newSubscriptions, subscriptions) == subscriptions)
}
// Create a new linked list where 'subscription has been removed from the linked list of 'subscriptions'.
- private static DiagnosticSubscription Remove(DiagnosticSubscription subscriptions, DiagnosticSubscription subscription)
+ private static DiagnosticSubscription? Remove(DiagnosticSubscription? subscriptions, DiagnosticSubscription subscription)
{
if (subscriptions == null)
{
lock (s_allListenersLock)
{
// Call back for each existing listener on the new callback (catch-up).
- for (DiagnosticListener cur = s_allListeners; cur != null; cur = cur._next)
+ for (DiagnosticListener? cur = s_allListeners; cur != null; cur = cur._next)
observer.OnNext(cur);
// Add the observer to the list of subscribers.
/// </summary>
internal class AllListenerSubscription : IDisposable
{
- internal AllListenerSubscription(AllListenerObservable owner, IObserver<DiagnosticListener> subscriber, AllListenerSubscription next)
+ internal AllListenerSubscription(AllListenerObservable owner, IObserver<DiagnosticListener> subscriber, AllListenerSubscription? next)
{
this._owner = owner;
this.Subscriber = subscriber;
private readonly AllListenerObservable _owner; // the list this is a member of.
internal readonly IObserver<DiagnosticListener> Subscriber;
- internal AllListenerSubscription Next;
+ internal AllListenerSubscription? Next;
}
- private AllListenerSubscription _subscriptions;
+ private AllListenerSubscription? _subscriptions;
#endregion
}
#endregion
- private IDisposable SubscribeInternal(IObserver<KeyValuePair<string, object>> observer,
- Predicate<string> isEnabled1Arg, Func<string, object, object, bool> isEnabled3Arg,
- Action<Activity, object> onActivityImport, Action<Activity, object> onActivityExport)
+ private IDisposable SubscribeInternal(IObserver<KeyValuePair<string, object?>> observer,
+ Predicate<string>? isEnabled1Arg, Func<string, object?, object?, bool>? isEnabled3Arg,
+ Action<Activity, object?>? onActivityImport, Action<Activity, object?>? onActivityExport)
{
// If we have been disposed, we silently ignore any subscriptions.
if (_disposed)
return newSubscription;
}
- private volatile DiagnosticSubscription _subscriptions;
- private DiagnosticListener _next; // We keep a linked list of all NotificationListeners (s_allListeners)
+ private volatile DiagnosticSubscription? _subscriptions;
+ private DiagnosticListener? _next; // We keep a linked list of all NotificationListeners (s_allListeners)
private bool _disposed; // Has Dispose been called?
- private static DiagnosticListener s_allListeners; // linked list of all instances of DiagnosticListeners.
- private static AllListenerObservable s_allListenerObservable; // to make callbacks to this object when listeners come into existence.
+ private static DiagnosticListener? s_allListeners; // linked list of all instances of DiagnosticListeners.
+ private static AllListenerObservable? s_allListenerObservable; // to make callbacks to this object when listeners come into existence.
private static readonly object s_allListenersLock = new object();
#if false
private static readonly DiagnosticListener s_default = new DiagnosticListener("DiagnosticListener.DefaultListener");
/// <param name="name">The name of the event being written.</param>
/// <param name="value">An object that represent the value being passed as a payload for the event.
/// This is often an anonymous type which contains several sub-values.</param>
- public abstract void Write(string name, object value);
+ public abstract void Write(string name, object? value);
/// <summary>
/// Optional: if there is expensive setup for the notification, you can call IsEnabled
/// Null by default. Consumers should expect to receive null which may indicate that producer
/// called pure IsEnabled(string) or producer passed all necessary context in arg1</param>
/// <seealso cref="IsEnabled(string)"/>
- public virtual bool IsEnabled(string name, object arg1, object arg2 = null)
+ public virtual bool IsEnabled(string name, object? arg1, object? arg2 = null)
{
return IsEnabled(name);
}
/// <param name="args">An object that represent the value being passed as a payload for the event.</param>
/// <returns>Started Activity for convenient chaining</returns>
/// <seealso cref="Activity"/>
- public Activity StartActivity(Activity activity, object args)
+ public Activity StartActivity(Activity activity, object? args)
{
activity.Start();
Write(activity.OperationName + ".Start", args);
/// <param name="activity">Activity to be stopped</param>
/// <param name="args">An object that represent the value being passed as a payload for the event.</param>
/// <seealso cref="Activity"/>
- public void StopActivity(Activity activity, object args)
+ public void StopActivity(Activity activity, object? args)
{
// Stop sets the end time if it was unset, but we want it set before we issue the write
// so we do it now.
}
/// <summary>
- /// Optional: If an instumentation site creating an new activity that was caused
+ /// Optional: If an instrumentation site creating an new activity that was caused
/// by something outside the process (e.g. an incomming HTTP request), then that site
/// will want to make a new activity and transfer state from that incoming request
- /// to the activity. To the extent possible this should be done by the instrumenation
+ /// to the activity. To the extent possible this should be done by the instrumentation
/// site (because it is a contract between Activity and the incomming request logic
- /// at the instrumenation site. However the instrumenation site can't handle policy
+ /// at the instrumentation site. However the instrumentation site can't handle policy
/// (for example if sampling is done exactly which requests should be sampled) For this
/// the instrumentation site needs to call back out to the logging system and ask it to
/// resolve policy (e.g. decide if the Activity's 'sampling' bit should be set) This
/// then have the opportunity to update this activity as desired.
///
/// Note that this callout is rarely used at instrumentation sites (only those sites
- /// that are on the 'boundry' of the process), and the instrumetation site will implement
+ /// that are on the 'boundry' of the process), and the instrumentation site will implement
/// some default policy (it sets the activity in SOME way), and so this method does not
/// need to be overriden if that default policy is fine. Thus this is call should
/// be used rare (but often important) cases.
/// particular instrumentation site and the subscriber will know the type of
/// the payload and thus cast it and decode it if it needs to.
/// </summary>
- public virtual void OnActivityImport(Activity activity, object payload) { }
+ public virtual void OnActivityImport(Activity activity, object? payload) { }
/// <summary>
- /// Optional: If an instumentation site is at a location where activities leave the
+ /// Optional: If an instrumentation site is at a location where activities leave the
/// process (e.g. an outgoing HTTP request), then that site will want to transfer state
/// from the activity to the outgoing request. To the extent possible this should be
- /// done by the instrumenationsite (because it is a contract between Activity and the
- /// ougoing request logic at the instrumenation site. However the instrumenation site
+ /// done by the instrumentation site (because it is a contract between Activity and the
+ /// outgoing request logic at the instrumentation site. However the instrumentation site
/// can't handle policy (for example whether activity information should be disabled,
/// or written in a older format for compatibility reasons). For this
/// the instrumentation site needs to call back out to the logging system and ask it to
///
/// Note that this callout is rarely used at instrumentation sites (only those sites
/// that are on an outgoing 'boundry' of the process). Moreover typically the default
- /// policy that the instrumenation site performs (transfer all activity state in a
+ /// policy that the instrumentation site performs (transfer all activity state in a
/// particular outgoing convention), is likely to be fine. This is only for cases
/// where that is a problem. Thus this is call should be used very rarely and is
/// mostly here for symetry with OnActivityImport and future-proofing.
/// particular instrumentation site and the subscriber should know the type of
/// the payload and thus cast it and decode it if it needs to.
/// </summary>
- public virtual void OnActivityExport(Activity activity, object payload) { }
+ public virtual void OnActivityExport(Activity activity, object? payload) { }
}
public partial class DiagnosticListener
{
- public override void OnActivityImport(Activity activity, object payload)
+ public override void OnActivityImport(Activity activity, object? payload)
{
- for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
+ for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
curSubscription.OnActivityImport?.Invoke(activity, payload);
}
- public override void OnActivityExport(Activity activity, object payload)
+ public override void OnActivityExport(Activity activity, object? payload)
{
- for (DiagnosticSubscription curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
+ for (DiagnosticSubscription? curSubscription = _subscriptions; curSubscription != null; curSubscription = curSubscription.Next)
curSubscription.OnActivityExport?.Invoke(activity, payload);
}
/// process (e.g. from Http Requests). These are called right after importing (exporting) the activity and
/// can be used to modify the activity (or outgoing request) to add policy.
/// </summary>
- public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object>> observer, Func<string, object, object, bool> isEnabled,
- Action<Activity, object> onActivityImport = null, Action<Activity, object> onActivityExport = null)
+ public virtual IDisposable Subscribe(IObserver<KeyValuePair<string, object?>> observer, Func<string, object?, object?, bool>? isEnabled,
+ Action<Activity, object?>? onActivityImport = null, Action<Activity, object?>? onActivityExport = null)
{
return isEnabled == null ?
SubscribeInternal(observer, null, null, onActivityImport, onActivityExport) :
/// Used to send ad-hoc diagnostics to humans.
/// </summary>
[Event(1, Keywords = Keywords.Messages)]
- public void Message(string Message)
+ public void Message(string? Message)
{
WriteEvent(1, Message);
}
/// Events from DiagnosticSource can be forwarded to EventSource using this event.
/// </summary>
[Event(2, Keywords = Keywords.Events)]
- private void Event(string SourceName, string EventName, IEnumerable<KeyValuePair<string, string>> Arguments)
+ private void Event(string SourceName, string EventName, IEnumerable<KeyValuePair<string, string?>>? Arguments)
{
WriteEvent(2, SourceName, EventName, Arguments);
}
if ((command.Command == EventCommand.Update || command.Command == EventCommand.Enable) &&
IsEnabled(EventLevel.Informational, Keywords.Events))
{
- string filterAndPayloadSpecs;
- command.Arguments.TryGetValue("FilterAndPayloadSpecs", out filterAndPayloadSpecs);
+ string? filterAndPayloadSpecs = null;
+ command.Arguments!.TryGetValue("FilterAndPayloadSpecs", out filterAndPayloadSpecs);
if (!IsEnabled(EventLevel.Informational, Keywords.IgnoreShortCutKeywords))
{
}
// trivial helper to allow you to join two strings the first of which can be null.
- private static string NewLineSeparate(string str1, string str2)
+ private static string NewLineSeparate(string? str1, string str2)
{
Debug.Assert(str2 != null);
if (string.IsNullOrEmpty(str1))
/// in the output payload, however this feature and be tuned off by prefixing the
/// PAYLOADSPEC with a '-'.
/// </summary>
- public static void CreateFilterAndTransformList(ref FilterAndTransform specList, string filterAndPayloadSpecs, DiagnosticSourceEventSource eventSource)
+ public static void CreateFilterAndTransformList(ref FilterAndTransform? specList, string? filterAndPayloadSpecs, DiagnosticSourceEventSource eventSource)
{
DestroyFilterAndTransformList(ref specList); // Stop anything that was on before.
if (filterAndPayloadSpecs == null)
/// This destroys (turns off) the FilterAndTransform stopping the forwarding started with CreateFilterAndTransformList
/// </summary>
/// <param name="specList"></param>
- public static void DestroyFilterAndTransformList(ref FilterAndTransform specList)
+ public static void DestroyFilterAndTransformList(ref FilterAndTransform? specList)
{
var curSpec = specList;
specList = null; // Null out the list
/// This FilterAndTransform will subscribe to DiagnosticSources specified by the specification and forward them to 'eventSource.
/// For convenience, the 'Next' field is set to the 'next' parameter, so you can easily form linked lists.
/// </summary>
- public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform next)
+ public FilterAndTransform(string filterAndPayloadSpec, int startIdx, int endIdx, DiagnosticSourceEventSource eventSource, FilterAndTransform? next)
{
Debug.Assert(filterAndPayloadSpec != null && startIdx >= 0 && startIdx <= endIdx && endIdx <= filterAndPayloadSpec.Length);
Next = next;
_eventSource = eventSource;
- string listenerNameFilter = null; // Means WildCard.
- string eventNameFilter = null; // Means WildCard.
- string activityName = null;
+ string? listenerNameFilter = null; // Means WildCard.
+ string? eventNameFilter = null; // Means WildCard.
+ string? activityName = null;
var startTransformIdx = startIdx;
var endEventNameIdx = endIdx;
}
}
- Action<string, string, IEnumerable<KeyValuePair<string, string>>> writeEvent = null;
+ Action<string, string, IEnumerable<KeyValuePair<string, string?>>>? writeEvent = null;
if (activityName != null && activityName.Contains("Activity"))
{
- MethodInfo writeEventMethodInfo = typeof(DiagnosticSourceEventSource).GetTypeInfo().GetDeclaredMethod(activityName);
+ MethodInfo? writeEventMethodInfo = typeof(DiagnosticSourceEventSource).GetTypeInfo().GetDeclaredMethod(activityName);
if (writeEventMethodInfo != null)
{
// This looks up the activityName (which needs to be a name of an event on DiagnosticSourceEventSource
// just works.
try
{
- writeEvent = (Action<string, string, IEnumerable<KeyValuePair<string, string>>>)
+ writeEvent = (Action<string?, string?, IEnumerable<KeyValuePair<string, string?>>>)
writeEventMethodInfo.CreateDelegate(typeof(Action<string, string, IEnumerable<KeyValuePair<string, string>>>), _eventSource);
}
catch (Exception) { }
if (listenerNameFilter == null || listenerNameFilter == newListener.Name)
{
_eventSource.NewDiagnosticListener(newListener.Name);
- Predicate<string> eventNameFilterPredicate = null;
+ Predicate<string>? eventNameFilterPredicate = null;
if (eventNameFilter != null)
eventNameFilterPredicate = (string eventName) => eventNameFilter == eventName;
- var subscription = newListener.Subscribe(new CallbackObserver<KeyValuePair<string, object>>(delegate (KeyValuePair<string, object> evnt)
+ var subscription = newListener.Subscribe(new CallbackObserver<KeyValuePair<string, object?>>(delegate (KeyValuePair<string, object?> evnt)
{
// The filter given to the DiagnosticSource may not work if users don't is 'IsEnabled' as expected.
// Thus we look for any events that may have snuck through and filter them out before forwarding.
if (_liveSubscriptions != null)
{
- var subscr = _liveSubscriptions;
+ Subscriptions? subscr = _liveSubscriptions;
_liveSubscriptions = null;
while (subscr != null)
{
}
}
- public List<KeyValuePair<string, string>> Morph(object args)
+ public List<KeyValuePair<string, string?>> Morph(object? args)
{
// Transform the args into a bag of key-value strings.
- var outputArgs = new List<KeyValuePair<string, string>>();
+ var outputArgs = new List<KeyValuePair<string, string?>>();
if (args != null)
{
if (!_noImplicitTransforms)
{
// given the type, fetch the implicit transforms for that type and put it in the implicitTransforms variable.
Type argType = args.GetType();
- TransformSpec implicitTransforms;
+ TransformSpec? implicitTransforms;
// First check the one-element cache _firstImplicitTransformsEntry
- ImplicitTransformEntry cacheEntry = _firstImplicitTransformsEntry;
+ ImplicitTransformEntry? cacheEntry = _firstImplicitTransformsEntry;
if (cacheEntry != null && cacheEntry.Type == argType)
{
implicitTransforms = cacheEntry.Transforms; // Yeah we hit the cache.
if (_implicitTransformsTable == null)
{
Interlocked.CompareExchange(ref _implicitTransformsTable,
- new ConcurrentDictionary<Type, TransformSpec>(1, 8), null);
+ new ConcurrentDictionary<Type, TransformSpec?>(1, 8), null);
}
implicitTransforms = _implicitTransformsTable.GetOrAdd(argType, type => MakeImplicitTransforms(type));
}
// implicitTransformas now fetched from cache or constructed, use it to Fetch all the implicit fields.
if (implicitTransforms != null)
{
- for (TransformSpec serializableArg = implicitTransforms; serializableArg != null; serializableArg = serializableArg.Next)
+ for (TransformSpec? serializableArg = implicitTransforms; serializableArg != null; serializableArg = serializableArg.Next)
outputArgs.Add(serializableArg.Morph(args));
}
}
if (_explicitTransforms != null)
{
- for (var explicitTransform = _explicitTransforms; explicitTransform != null; explicitTransform = explicitTransform.Next)
+ for (TransformSpec? explicitTransform = _explicitTransforms; explicitTransform != null; explicitTransform = explicitTransform.Next)
{
var keyValue = explicitTransform.Morph(args);
if (keyValue.Value != null)
return outputArgs;
}
- public FilterAndTransform Next;
+ public FilterAndTransform? Next;
#region private
// Given a type generate all the implicit transforms for type (that is for every field
// generate the spec that fetches it).
- private static TransformSpec MakeImplicitTransforms(Type type)
+ private static TransformSpec? MakeImplicitTransforms(Type type)
{
- TransformSpec newSerializableArgs = null;
+ TransformSpec? newSerializableArgs = null;
TypeInfo curTypeInfo = type.GetTypeInfo();
foreach (PropertyInfo property in curTypeInfo.DeclaredProperties)
{
}
// Reverses a linked list (of TransformSpecs) in place.
- private static TransformSpec Reverse(TransformSpec list)
+ private static TransformSpec? Reverse(TransformSpec? list)
{
- TransformSpec ret = null;
+ TransformSpec? ret = null;
while (list != null)
{
var next = list.Next;
return ret;
}
- private IDisposable _diagnosticsListenersSubscription; // This is our subscription that listens for new Diagnostic source to appear.
- private Subscriptions _liveSubscriptions; // These are the subscriptions that we are currently forwarding to the EventSource.
+ private IDisposable? _diagnosticsListenersSubscription; // This is our subscription that listens for new Diagnostic source to appear.
+ private Subscriptions? _liveSubscriptions; // These are the subscriptions that we are currently forwarding to the EventSource.
private readonly bool _noImplicitTransforms; // Listener can say they don't want implicit transforms.
- private ImplicitTransformEntry _firstImplicitTransformsEntry; // The transform for _firstImplicitFieldsType
- private ConcurrentDictionary<Type, TransformSpec> _implicitTransformsTable; // If there is more than one object type for an implicit transform, they go here.
- private readonly TransformSpec _explicitTransforms; // payload to include because the user explicitly indicated how to fetch the field.
+ private ImplicitTransformEntry? _firstImplicitTransformsEntry; // The transform for _firstImplicitFieldsType
+ private ConcurrentDictionary<Type, TransformSpec?>? _implicitTransformsTable; // If there is more than one object type for an implicit transform, they go here.
+ private readonly TransformSpec? _explicitTransforms; // payload to include because the user explicitly indicated how to fetch the field.
private readonly DiagnosticSourceEventSource _eventSource; // Where the data is written to.
#endregion
}
// We remember this type-transform pair in the _firstImplicitTransformsEntry cache.
internal class ImplicitTransformEntry
{
- public Type Type;
- public TransformSpec Transforms;
+ public Type? Type;
+ public TransformSpec? Transforms;
}
/// <summary>
/// parse the strings 'spec' from startIdx to endIdx (points just beyond the last considered char)
/// The syntax is ID1=ID2.ID3.ID4 .... Where ID1= is optional.
/// </summary>
- public TransformSpec(string transformSpec, int startIdx, int endIdx, TransformSpec next = null)
+ public TransformSpec(string transformSpec, int startIdx, int endIdx, TransformSpec? next = null)
{
Debug.Assert(transformSpec != null && startIdx >= 0 && startIdx < endIdx && endIdx <= transformSpec.Length);
Next = next;
/// if the spec is OUTSTR=EVENT_VALUE.PROP1.PROP2.PROP3 and the ultimate value of PROP3 is
/// 10 then the return key value pair is KeyValuePair("OUTSTR","10")
/// </summary>
- public KeyValuePair<string, string> Morph(object obj)
+ public KeyValuePair<string, string?> Morph(object? obj)
{
- for (PropertySpec cur = _fetches; cur != null; cur = cur.Next)
+ for (PropertySpec? cur = _fetches; cur != null; cur = cur.Next)
{
if (obj != null)
obj = cur.Fetch(obj);
}
- return new KeyValuePair<string, string>(_outputName, obj?.ToString());
+ return new KeyValuePair<string, string?>(_outputName, obj?.ToString());
}
/// <summary>
/// A public field that can be used to form a linked list.
/// </summary>
- public TransformSpec Next;
+ public TransformSpec? Next;
#region private
/// <summary>
/// For convenience you can set he 'next' field to form a linked
/// list of PropertySpecs.
/// </summary>
- public PropertySpec(string propertyName, PropertySpec next = null)
+ public PropertySpec(string propertyName, PropertySpec? next = null)
{
Next = next;
_propertyName = propertyName;
/// <summary>
/// Given an object fetch the property that this PropertySpec represents.
/// </summary>
- public object Fetch(object obj)
+ public object? Fetch(object obj)
{
Type objType = obj.GetType();
- PropertyFetch fetch = _fetchForExpectedType;
+ PropertyFetch? fetch = _fetchForExpectedType;
if (fetch == null || fetch.Type != objType)
{
_fetchForExpectedType = fetch = PropertyFetch.FetcherForProperty(
objType, objType.GetTypeInfo().GetDeclaredProperty(_propertyName));
}
- return fetch.Fetch(obj);
+ return fetch!.Fetch(obj);
}
/// <summary>
/// A public field that can be used to form a linked list.
/// </summary>
- public PropertySpec Next;
+ public PropertySpec? Next;
#region private
/// <summary>
/// Create a property fetcher from a .NET Reflection PropertyInfo class that
/// represents a property of a particular type.
/// </summary>
- public static PropertyFetch FetcherForProperty(Type type, PropertyInfo propertyInfo)
+ public static PropertyFetch? FetcherForProperty(Type type, PropertyInfo? propertyInfo)
{
if (propertyInfo == null)
return new PropertyFetch(type); // returns null on any fetch.
var typedPropertyFetcher = typeof(TypedFetchProperty<,>);
var instantiatedTypedPropertyFetcher = typedPropertyFetcher.GetTypeInfo().MakeGenericType(
- propertyInfo.DeclaringType, propertyInfo.PropertyType);
- return (PropertyFetch)Activator.CreateInstance(instantiatedTypedPropertyFetcher, type, propertyInfo);
+ propertyInfo.DeclaringType!, propertyInfo.PropertyType);
+ return (PropertyFetch?)Activator.CreateInstance(instantiatedTypedPropertyFetcher, type, propertyInfo);
}
/// <summary>
/// Given an object, fetch the property that this propertyFech represents.
/// </summary>
- public virtual object Fetch(object obj) { return null; }
+ public virtual object? Fetch(object obj) { return null; }
#region private
{
public TypedFetchProperty(Type type, PropertyInfo property) : base(type)
{
- _propertyFetch = (Func<TObject, TProperty>)property.GetMethod.CreateDelegate(typeof(Func<TObject, TProperty>));
+ _propertyFetch = (Func<TObject, TProperty>)property.GetMethod!.CreateDelegate(typeof(Func<TObject, TProperty>));
}
- public override object Fetch(object obj)
+ public override object? Fetch(object obj)
{
return _propertyFetch((TObject)obj);
}
}
private readonly string _propertyName;
- private volatile PropertyFetch _fetchForExpectedType;
+ private volatile PropertyFetch? _fetchForExpectedType;
#endregion
}
- private readonly string _outputName;
- private readonly PropertySpec _fetches;
+ private readonly string _outputName = null!;
+ private readonly PropertySpec? _fetches;
#endregion
}
// We use this linked list for thread atomicity
internal class Subscriptions
{
- public Subscriptions(IDisposable subscription, Subscriptions next)
+ public Subscriptions(IDisposable subscription, Subscriptions? next)
{
Subscription = subscription;
Next = next;
}
public IDisposable Subscription;
- public Subscriptions Next;
+ public Subscriptions? Next;
}
#endregion
- private FilterAndTransform _specs; // Transformation specifications that indicate which sources/events are forwarded.
+ private FilterAndTransform? _specs; // Transformation specifications that indicate which sources/events are forwarded.
#endregion
}
}