Annotate System.Transactions.Local for nullable (dotnet/corefx#42465)
authorbuyaa-n <buyankhishig.namnan@microsoft.com>
Wed, 13 Nov 2019 05:59:33 +0000 (21:59 -0800)
committerSantiago Fernandez Madero <safern@microsoft.com>
Wed, 13 Nov 2019 05:59:33 +0000 (21:59 -0800)
* Annotate System.Transactions.Local for nullable

* Reverting assert on Transaction.State property and make it nullabe

* Small udpates

* Applying feedback

* Applying feedback

* Update src/System.Transactions.Local/src/System/Transactions/Transaction.cs

Co-Authored-By: Santiago Fernandez Madero <safern@microsoft.com>
Commit migrated from https://github.com/dotnet/corefx/commit/8f8b895f843e2b659c8a722c3e38548cfecdb271

28 files changed:
src/libraries/System.Transactions.Local/ref/System.Transactions.Local.cs
src/libraries/System.Transactions.Local/ref/System.Transactions.Local.csproj
src/libraries/System.Transactions.Local/src/System.Transactions.Local.csproj
src/libraries/System.Transactions.Local/src/System/Transactions/CommittableTransaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DependentTransaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DistributedTransaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/DurableEnlistmentState.cs
src/libraries/System.Transactions.Local/src/System/Transactions/Enlistment.cs
src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentState.cs
src/libraries/System.Transactions.Local/src/System/Transactions/EnlistmentTraceIdentifier.cs
src/libraries/System.Transactions.Local/src/System/Transactions/EnterpriseServices.cs
src/libraries/System.Transactions.Local/src/System/Transactions/ITransactionPromoter.cs
src/libraries/System.Transactions.Local/src/System/Transactions/InternalTransaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/PreparingEnlistment.cs
src/libraries/System.Transactions.Local/src/System/Transactions/SinglePhaseEnlistment.cs
src/libraries/System.Transactions.Local/src/System/Transactions/Transaction.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionException.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInformation.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionInterop.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionManager.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionOptions.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionScope.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionState.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTable.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionTraceIdentifier.cs
src/libraries/System.Transactions.Local/src/System/Transactions/TransactionsEtwProvider.cs
src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentMultiplexing.cs
src/libraries/System.Transactions.Local/src/System/Transactions/VolatileEnlistmentState.cs

index 00ef78a..4ca3840 100644 (file)
@@ -12,11 +12,11 @@ namespace System.Transactions
         public CommittableTransaction() { }
         public CommittableTransaction(System.TimeSpan timeout) { }
         public CommittableTransaction(System.Transactions.TransactionOptions options) { }
-        object System.IAsyncResult.AsyncState { get { throw null; } }
+        object? System.IAsyncResult.AsyncState { get { throw null; } }
         System.Threading.WaitHandle System.IAsyncResult.AsyncWaitHandle { get { throw null; } }
         bool System.IAsyncResult.CompletedSynchronously { get { throw null; } }
         bool System.IAsyncResult.IsCompleted { get { throw null; } }
-        public System.IAsyncResult BeginCommit(System.AsyncCallback asyncCallback, object asyncState) { throw null; }
+        public System.IAsyncResult BeginCommit(System.AsyncCallback? asyncCallback, object? asyncState) { throw null; }
         public void Commit() { }
         public void EndCommit(System.IAsyncResult asyncResult) { }
     }
@@ -47,7 +47,7 @@ namespace System.Transactions
         Automatic = 1,
         Full = 2,
     }
-    public delegate System.Transactions.Transaction HostCurrentTransactionCallback();
+    public delegate System.Transactions.Transaction? HostCurrentTransactionCallback();
     [System.Runtime.InteropServices.InterfaceTypeAttribute(System.Runtime.InteropServices.ComInterfaceType.InterfaceIsIUnknown)]
     public partial interface IDtcTransaction
     {
@@ -88,13 +88,13 @@ namespace System.Transactions
     }
     public partial interface ITransactionPromoter
     {
-        byte[] Promote();
+        byte[]? Promote();
     }
     public partial class PreparingEnlistment : System.Transactions.Enlistment
     {
         internal PreparingEnlistment() { }
         public void ForceRollback() { }
-        public void ForceRollback(System.Exception e) { }
+        public void ForceRollback(System.Exception? e) { }
         public void Prepared() { }
         public byte[] RecoveryInformation() { throw null; }
     }
@@ -102,10 +102,10 @@ namespace System.Transactions
     {
         internal SinglePhaseEnlistment() { }
         public void Aborted() { }
-        public void Aborted(System.Exception e) { }
+        public void Aborted(System.Exception? e) { }
         public void Committed() { }
         public void InDoubt() { }
-        public void InDoubt(System.Exception e) { }
+        public void InDoubt(System.Exception? e) { }
     }
     public sealed partial class SubordinateTransaction : System.Transactions.Transaction
     {
@@ -114,11 +114,11 @@ namespace System.Transactions
     public partial class Transaction : System.IDisposable, System.Runtime.Serialization.ISerializable
     {
         internal Transaction() { }
-        public static System.Transactions.Transaction Current { get { throw null; } set { } }
+        public static System.Transactions.Transaction? Current { get { throw null; } set { } }
         public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } }
         public System.Guid PromoterType { get { throw null; } }
         public System.Transactions.TransactionInformation TransactionInformation { get { throw null; } }
-        public event System.Transactions.TransactionCompletedEventHandler TransactionCompleted { add { } remove { } }
+        public event System.Transactions.TransactionCompletedEventHandler? TransactionCompleted { add { } remove { } }
         public System.Transactions.Transaction Clone() { throw null; }
         public System.Transactions.DependentTransaction DependentClone(System.Transactions.DependentCloneOption cloneOption) { throw null; }
         public void Dispose() { }
@@ -128,14 +128,14 @@ namespace System.Transactions
         public bool EnlistPromotableSinglePhase(System.Transactions.IPromotableSinglePhaseNotification promotableSinglePhaseNotification, System.Guid promoterType) { throw null; }
         public System.Transactions.Enlistment EnlistVolatile(System.Transactions.IEnlistmentNotification enlistmentNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { throw null; }
         public System.Transactions.Enlistment EnlistVolatile(System.Transactions.ISinglePhaseNotification singlePhaseNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { 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 byte[] GetPromotedToken() { throw null; }
-        public static bool operator ==(System.Transactions.Transaction x, System.Transactions.Transaction y) { throw null; }
-        public static bool operator !=(System.Transactions.Transaction x, System.Transactions.Transaction y) { throw null; }
+        public static bool operator ==(System.Transactions.Transaction? x, System.Transactions.Transaction? y) { throw null; }
+        public static bool operator !=(System.Transactions.Transaction? x, System.Transactions.Transaction? y) { throw null; }
         public System.Transactions.Enlistment PromoteAndEnlistDurable(System.Guid resourceManagerIdentifier, System.Transactions.IPromotableSinglePhaseNotification promotableNotification, System.Transactions.ISinglePhaseNotification enlistmentNotification, System.Transactions.EnlistmentOptions enlistmentOptions) { throw null; }
         public void Rollback() { }
-        public void Rollback(System.Exception e) { }
+        public void Rollback(System.Exception? e) { }
         public void SetDistributedTransactionIdentifier(System.Transactions.IPromotableSinglePhaseNotification promotableNotification, System.Guid distributedTransactionIdentifier) { }
         void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext context) { }
     }
@@ -143,28 +143,28 @@ namespace System.Transactions
     {
         public TransactionAbortedException() { }
         protected TransactionAbortedException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
-        public TransactionAbortedException(string message) { }
-        public TransactionAbortedException(string message, System.Exception innerException) { }
+        public TransactionAbortedException(string? message) { }
+        public TransactionAbortedException(string? message, System.Exception? innerException) { }
     }
-    public delegate void TransactionCompletedEventHandler(object sender, System.Transactions.TransactionEventArgs e);
+    public delegate void TransactionCompletedEventHandler(object? sender, System.Transactions.TransactionEventArgs e);
     public partial class TransactionEventArgs : System.EventArgs
     {
         public TransactionEventArgs() { }
-        public System.Transactions.Transaction Transaction { get { throw null; } }
+        public System.Transactions.Transaction? Transaction { get { throw null; } }
     }
     public partial class TransactionException : System.SystemException
     {
         public TransactionException() { }
         protected TransactionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
-        public TransactionException(string message) { }
-        public TransactionException(string message, System.Exception innerException) { }
+        public TransactionException(string? message) { }
+        public TransactionException(string? message, System.Exception? innerException) { }
     }
     public partial class TransactionInDoubtException : System.Transactions.TransactionException
     {
         public TransactionInDoubtException() { }
         protected TransactionInDoubtException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
-        public TransactionInDoubtException(string message) { }
-        public TransactionInDoubtException(string message, System.Exception innerException) { }
+        public TransactionInDoubtException(string? message) { }
+        public TransactionInDoubtException(string? message, System.Exception? innerException) { }
     }
     public partial class TransactionInformation
     {
@@ -188,9 +188,10 @@ namespace System.Transactions
     public static partial class TransactionManager
     {
         public static System.TimeSpan DefaultTimeout { get { throw null; } }
-        public static System.Transactions.HostCurrentTransactionCallback HostCurrentCallback { get { throw null; } set { } }
+        [System.Diagnostics.CodeAnalysis.DisallowNullAttribute]
+        public static System.Transactions.HostCurrentTransactionCallback? HostCurrentCallback { get { throw null; } set { } }
         public static System.TimeSpan MaximumTimeout { get { throw null; } }
-        public static event System.Transactions.TransactionStartedEventHandler DistributedTransactionStarted { add { } remove { } }
+        public static event System.Transactions.TransactionStartedEventHandler? DistributedTransactionStarted { add { } remove { } }
         public static void RecoveryComplete(System.Guid resourceManagerIdentifier) { }
         public static System.Transactions.Enlistment Reenlist(System.Guid resourceManagerIdentifier, byte[] recoveryInformation, System.Transactions.IEnlistmentNotification enlistmentNotification) { throw null; }
     }
@@ -198,15 +199,15 @@ namespace System.Transactions
     {
         public TransactionManagerCommunicationException() { }
         protected TransactionManagerCommunicationException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
-        public TransactionManagerCommunicationException(string message) { }
-        public TransactionManagerCommunicationException(string message, System.Exception innerException) { }
+        public TransactionManagerCommunicationException(string? message) { }
+        public TransactionManagerCommunicationException(string? message, System.Exception? innerException) { }
     }
     public partial struct TransactionOptions
     {
         private int _dummyPrimitive;
         public System.Transactions.IsolationLevel IsolationLevel { get { throw null; } set { } }
         public System.TimeSpan Timeout { get { throw null; } set { } }
-        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.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; }
         public static bool operator !=(System.Transactions.TransactionOptions x, System.Transactions.TransactionOptions y) { throw null; }
@@ -215,8 +216,8 @@ namespace System.Transactions
     {
         public TransactionPromotionException() { }
         protected TransactionPromotionException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) { }
-        public TransactionPromotionException(string message) { }
-        public TransactionPromotionException(string message, System.Exception innerException) { }
+        public TransactionPromotionException(string? message) { }
+        public TransactionPromotionException(string? message, System.Exception? innerException) { }
     }
     public sealed partial class TransactionScope : System.IDisposable
     {
@@ -248,7 +249,7 @@ namespace System.Transactions
         RequiresNew = 1,
         Suppress = 2,
     }
-    public delegate void TransactionStartedEventHandler(object sender, System.Transactions.TransactionEventArgs e);
+    public delegate void TransactionStartedEventHandler(object? sender, System.Transactions.TransactionEventArgs e);
     public enum TransactionStatus
     {
         Active = 0,
index 33cd04b..5de24ad 100644 (file)
@@ -2,6 +2,7 @@
   <PropertyGroup>
     <OutputType>Library</OutputType>
     <Configurations>netcoreapp-Debug;netcoreapp-Release</Configurations>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System.Transactions.Local.cs" />
index f275f2a..6f8fdc1 100644 (file)
@@ -3,6 +3,7 @@
     <IsPartialFacadeAssembly>true</IsPartialFacadeAssembly>
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <Configurations>netcoreapp-Debug;netcoreapp-Release</Configurations>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <!-- Default configurations to help VS understand the options -->
   <ItemGroup>
index 68d8eb6..f564ba4 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
 using System.Threading;
 
 namespace System.Transactions
@@ -26,7 +27,7 @@ namespace System.Transactions
         {
         }
 
-        internal CommittableTransaction(IsolationLevel isoLevel, TimeSpan timeout) : base(isoLevel, (InternalTransaction)null)
+        internal CommittableTransaction(IsolationLevel isoLevel, TimeSpan timeout) : base(isoLevel, (InternalTransaction?)null)
         {
             // object to use for synchronization rather than locking on a public object
             _internalTransaction = new InternalTransaction(timeout, this);
@@ -42,7 +43,7 @@ namespace System.Transactions
             }
         }
 
-        public IAsyncResult BeginCommit(AsyncCallback asyncCallback, object asyncState)
+        public IAsyncResult BeginCommit(AsyncCallback? asyncCallback, object? asyncState)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -63,6 +64,7 @@ namespace System.Transactions
                     throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
                 }
 
+                Debug.Assert(_internalTransaction.State != null);
                 // this.complete will get set to true when the transaction enters a state that is
                 // beyond Phase0.
                 _internalTransaction.State.BeginCommit(_internalTransaction, true, asyncCallback, asyncState);
@@ -99,6 +101,7 @@ namespace System.Transactions
                     throw TransactionException.CreateTransactionCompletedException(DistributedTxId);
                 }
 
+                Debug.Assert(_internalTransaction.State != null);
                 _internalTransaction.State.BeginCommit(_internalTransaction, false, null, null);
 
                 // now that commit has started wait for the monitor on the transaction to know
@@ -134,6 +137,7 @@ namespace System.Transactions
                 return;
             }
 
+            Debug.Assert(_internalTransaction.State != null);
             if (_internalTransaction.State.get_Status(_internalTransaction) == TransactionStatus.Active)
             {
                 lock (_internalTransaction)
@@ -173,6 +177,7 @@ namespace System.Transactions
             {
                 do
                 {
+                    Debug.Assert(_internalTransaction.State != null);
                     if (_internalTransaction.State.IsCompleted(_internalTransaction))
                     {
                         break;
@@ -188,7 +193,7 @@ namespace System.Transactions
             }
         }
 
-        object IAsyncResult.AsyncState => _internalTransaction._asyncState;
+        object? IAsyncResult.AsyncState => _internalTransaction._asyncState;
 
         bool IAsyncResult.CompletedSynchronously => _completedSynchronously;
 
@@ -202,6 +207,7 @@ namespace System.Transactions
                     {
                         if (_internalTransaction._asyncResultEvent == null)
                         {
+                            Debug.Assert(_internalTransaction.State != null);
                             // Demand create an event that is already signaled if the transaction has completed.
                             ManualResetEvent temp = new ManualResetEvent(
                                 _internalTransaction.State.get_Status(_internalTransaction) != TransactionStatus.Active);
@@ -221,6 +227,7 @@ namespace System.Transactions
             {
                 lock (_internalTransaction)
                 {
+                    Debug.Assert(_internalTransaction.State != null);
                     return _internalTransaction.State.get_Status(_internalTransaction) != TransactionStatus.Active;
                 }
             }
index 1a86259..4ca8232 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
 
 namespace System.Transactions
 {
@@ -18,6 +19,7 @@ namespace System.Transactions
             _blocking = blocking;
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 if (blocking)
                 {
                     _internalTransaction.State.CreateBlockingClone(_internalTransaction);
@@ -51,6 +53,7 @@ namespace System.Transactions
 
                 _complete = true;
 
+                Debug.Assert(_internalTransaction.State != null);
                 if (_blocking)
                 {
                     _internalTransaction.State.CompleteBlockingClone(_internalTransaction);
index c814e35..3735d51 100644 (file)
@@ -8,7 +8,7 @@ namespace System.Transactions.Distributed
 {
     internal sealed class DistributedTransactionManager
     {
-        internal object NodeName { get; set; }
+        internal object? NodeName { get; set; }
 
         internal IPromotedEnlistment ReenlistTransaction(Guid resourceManagerIdentifier, byte[] resourceManagerRecoveryInformation, RecoveringInternalEnlistment internalEnlistment)
         {
@@ -74,12 +74,12 @@ namespace System.Transactions.Distributed
             throw new PlatformNotSupportedException();
         }
 
-        internal Exception InnerException { get; set; }
+        internal Exception? InnerException { get; set; }
         internal Guid Identifier { get; set; }
-        internal RealDistributedTransaction RealTransaction { get; set; }
+        internal RealDistributedTransaction? RealTransaction { get; set; }
         internal TransactionTraceIdentifier TransactionTraceId { get; set; }
         internal IsolationLevel IsolationLevel { get; set; }
-        internal Transaction SavedLtmPromotedTransaction { get; set; }
+        internal Transaction? SavedLtmPromotedTransaction { get; set; }
 
         internal void Dispose()
         {
@@ -149,7 +149,7 @@ namespace System.Transactions.Distributed
 
         internal class RealDistributedTransaction
         {
-            internal InternalTransaction InternalTransaction { get; set; }
+            internal InternalTransaction? InternalTransaction { get; set; }
         }
     }
 
index 0b7dbea..1afd579 100644 (file)
@@ -10,14 +10,14 @@ namespace System.Transactions
     // Base class for all durable enlistment states
     internal abstract class DurableEnlistmentState : EnlistmentState
     {
-        private static DurableEnlistmentActive s_durableEnlistmentActive;
-        private static DurableEnlistmentAborting s_durableEnlistmentAborting;
-        private static DurableEnlistmentCommitting s_durableEnlistmentCommitting;
-        private static DurableEnlistmentDelegated s_durableEnlistmentDelegated;
-        private static DurableEnlistmentEnded s_durableEnlistmentEnded;
+        private static DurableEnlistmentActive? s_durableEnlistmentActive;
+        private static DurableEnlistmentAborting? s_durableEnlistmentAborting;
+        private static DurableEnlistmentCommitting? s_durableEnlistmentCommitting;
+        private static DurableEnlistmentDelegated? s_durableEnlistmentDelegated;
+        private static DurableEnlistmentEnded? s_durableEnlistmentEnded;
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
 
         internal static DurableEnlistmentActive DurableEnlistmentActive =>
             LazyInitializer.EnsureInitialized(ref s_durableEnlistmentActive, ref s_classSyncObject, () => new DurableEnlistmentActive());
@@ -116,7 +116,7 @@ namespace System.Transactions
             }
         }
 
-        internal override void Aborted(InternalEnlistment enlistment, Exception e)
+        internal override void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             if (enlistment.Transaction._innerException == null)
             {
@@ -183,6 +183,7 @@ namespace System.Transactions
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Make the transaction commit
             enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction);
         }
@@ -192,20 +193,22 @@ namespace System.Transactions
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Make the transaction commit
             enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction);
         }
 
-        internal override void Aborted(InternalEnlistment enlistment, Exception e)
+        internal override void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Start the transaction aborting
             enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e);
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
@@ -215,6 +218,7 @@ namespace System.Transactions
                 enlistment.Transaction._innerException = e;
             }
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Make the transaction in dobut
             enlistment.Transaction.State.InDoubtFromEnlistment(enlistment.Transaction);
         }
@@ -239,11 +243,12 @@ namespace System.Transactions
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Change the transaction to committed.
             enlistment.Transaction.State.ChangeStatePromotedCommitted(enlistment.Transaction);
         }
 
-        internal override void Aborted(InternalEnlistment enlistment, Exception e)
+        internal override void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
@@ -253,11 +258,12 @@ namespace System.Transactions
                 enlistment.Transaction._innerException = e;
             }
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Start the transaction aborting
             enlistment.Transaction.State.ChangeStatePromotedAborted(enlistment.Transaction);
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             // Transition to the ended state
             DurableEnlistmentEnded.EnterState(enlistment);
@@ -267,6 +273,7 @@ namespace System.Transactions
                 enlistment.Transaction._innerException = e;
             }
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Tell the transaction that the enlistment is InDoubt.  Note that
             // for a transaction that has been delegated and then promoted there
             // are two chances to get a better answer than indoubt.  So it may be that
@@ -292,7 +299,7 @@ namespace System.Transactions
             // it already knows.  Eat this message.
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             // Ignore this in case the enlistment gets here before
             // the transaction tells it to do so
index 6ead235..c9372f0 100644 (file)
@@ -16,17 +16,17 @@ namespace System.Transactions
 
         void ForceRollback();
 
-        void ForceRollback(Exception e);
+        void ForceRollback(Exception? e);
 
         void Committed();
 
         void Aborted();
 
-        void Aborted(Exception e);
+        void Aborted(Exception? e);
 
         void InDoubt();
 
-        void InDoubt(Exception e);
+        void InDoubt(Exception? e);
 
         byte[] GetRecoveryInformation();
 
@@ -45,20 +45,20 @@ namespace System.Transactions
     internal class InternalEnlistment : ISinglePhaseNotificationInternal
     {
         // Storage for the state of the enlistment.
-        internal EnlistmentState _twoPhaseState;
+        internal EnlistmentState? _twoPhaseState;
 
         // Interface implemented by the enlistment owner for notifications
-        protected IEnlistmentNotification _twoPhaseNotifications;
+        protected IEnlistmentNotification? _twoPhaseNotifications;
 
         // Store a reference to the single phase notification interface in case
         // the enlisment supports it.
-        protected ISinglePhaseNotification _singlePhaseNotifications;
+        protected ISinglePhaseNotification? _singlePhaseNotifications;
 
         // Reference to the containing transaction.
-        protected InternalTransaction _transaction;
+        protected InternalTransaction _transaction = null!;
 
         // Reference to the lightweight transaction.
-        private readonly Transaction _atomicTransaction;
+        private readonly Transaction? _atomicTransaction;
 
         // The EnlistmentTraceIdentifier for this enlistment.
         private EnlistmentTraceIdentifier _traceIdentifier;
@@ -82,11 +82,11 @@ namespace System.Transactions
 
         // Parent Enlistment Object
         private readonly Enlistment _enlistment;
-        private PreparingEnlistment _preparingEnlistment;
-        private SinglePhaseEnlistment _singlePhaseEnlistment;
+        private PreparingEnlistment? _preparingEnlistment;
+        private SinglePhaseEnlistment? _singlePhaseEnlistment;
 
         // If this enlistment is promoted store the object it delegates to.
-        private IPromotedEnlistment _promotedEnlistment;
+        private IPromotedEnlistment? _promotedEnlistment;
 
         // For Recovering Enlistments
         protected InternalEnlistment(Enlistment enlistment, IEnlistmentNotification twoPhaseNotifications)
@@ -113,7 +113,7 @@ namespace System.Transactions
             Enlistment enlistment,
             InternalTransaction transaction,
             IEnlistmentNotification twoPhaseNotifications,
-            ISinglePhaseNotification singlePhaseNotifications,
+            ISinglePhaseNotification? singlePhaseNotifications,
             Transaction atomicTransaction)
         {
             _enlistment = enlistment;
@@ -139,7 +139,10 @@ namespace System.Transactions
 
         internal EnlistmentState State
         {
-            get { return _twoPhaseState; }
+            get {
+                Debug.Assert(_twoPhaseState != null);
+                return _twoPhaseState;
+            }
             set { _twoPhaseState = value; }
         }
 
@@ -182,9 +185,9 @@ namespace System.Transactions
             }
         }
 
-        internal IEnlistmentNotification EnlistmentNotification => _twoPhaseNotifications;
+        internal IEnlistmentNotification? EnlistmentNotification => _twoPhaseNotifications;
 
-        internal ISinglePhaseNotification SinglePhaseNotification => _singlePhaseNotifications;
+        internal ISinglePhaseNotification? SinglePhaseNotification => _singlePhaseNotifications;
 
         internal virtual IPromotableSinglePhaseNotification PromotableSinglePhaseNotification
         {
@@ -195,7 +198,7 @@ namespace System.Transactions
             }
         }
 
-        internal IPromotedEnlistment PromotedEnlistment
+        internal IPromotedEnlistment? PromotedEnlistment
         {
             get { return _promotedEnlistment; }
             set { _promotedEnlistment = value; }
@@ -255,7 +258,7 @@ namespace System.Transactions
             if (Transaction._phase0Volatiles._preparedVolatileEnlistments ==
                 Transaction._phase0VolatileWaveCount + Transaction._phase0Volatiles._dependentClones)
             {
-                Transaction.State.Phase0VolatilePrepareDone(Transaction);
+                Transaction.State!.Phase0VolatilePrepareDone(Transaction);
             }
         }
 
@@ -274,6 +277,7 @@ namespace System.Transactions
             _promotedEnlistment = singlePhaseEnlistment;
             try
             {
+                Debug.Assert(_singlePhaseNotifications != null);
                 _singlePhaseNotifications.SinglePhaseCommit(SinglePhaseEnlistment);
                 spcCommitted = true;
             }
@@ -290,6 +294,7 @@ namespace System.Transactions
             IPromotedEnlistment preparingEnlistment
             )
         {
+            Debug.Assert(_twoPhaseNotifications != null);
             _promotedEnlistment = preparingEnlistment;
             _twoPhaseNotifications.Prepare(PreparingEnlistment);
         }
@@ -298,6 +303,7 @@ namespace System.Transactions
             IPromotedEnlistment enlistment
             )
         {
+            Debug.Assert(_twoPhaseNotifications != null);
             _promotedEnlistment = enlistment;
             _twoPhaseNotifications.Commit(Enlistment);
         }
@@ -306,6 +312,7 @@ namespace System.Transactions
             IPromotedEnlistment enlistment
             )
         {
+            Debug.Assert(_twoPhaseNotifications != null);
             _promotedEnlistment = enlistment;
             _twoPhaseNotifications.Rollback(Enlistment);
         }
@@ -314,6 +321,7 @@ namespace System.Transactions
             IPromotedEnlistment enlistment
             )
         {
+            Debug.Assert(_twoPhaseNotifications != null);
             _promotedEnlistment = enlistment;
             _twoPhaseNotifications.InDoubt(Enlistment);
         }
@@ -329,7 +337,7 @@ namespace System.Transactions
             Guid resourceManagerIdentifier,
             InternalTransaction transaction,
             IEnlistmentNotification twoPhaseNotifications,
-            ISinglePhaseNotification singlePhaseNotifications,
+            ISinglePhaseNotification? singlePhaseNotifications,
             Transaction atomicTransaction) :
             base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction)
         {
@@ -389,7 +397,7 @@ namespace System.Transactions
             Enlistment enlistment,
             InternalTransaction transaction,
             IEnlistmentNotification twoPhaseNotifications,
-            ISinglePhaseNotification singlePhaseNotifications,
+            ISinglePhaseNotification? singlePhaseNotifications,
             Transaction atomicTransaction)
             : base(enlistment, transaction, twoPhaseNotifications, singlePhaseNotifications, atomicTransaction)
         {
@@ -414,7 +422,7 @@ namespace System.Transactions
                 _transaction._phase1Volatiles._volatileEnlistmentCount +
                 _transaction._phase1Volatiles._dependentClones)
             {
-                _transaction.State.Phase1VolatilePrepareDone(_transaction);
+                _transaction.State!.Phase1VolatilePrepareDone(_transaction);
             }
         }
     }
@@ -433,7 +441,7 @@ namespace System.Transactions
             Guid resourceManagerIdentifier,
             InternalTransaction transaction,
             IEnlistmentNotification twoPhaseNotifications,
-            ISinglePhaseNotification singlePhaseNotifications,
+            ISinglePhaseNotification? singlePhaseNotifications,
             Transaction atomicTransaction)
         {
             _internalEnlistment = new DurableInternalEnlistment(
@@ -449,7 +457,7 @@ namespace System.Transactions
         internal Enlistment(
             InternalTransaction transaction,
             IEnlistmentNotification twoPhaseNotifications,
-            ISinglePhaseNotification singlePhaseNotifications,
+            ISinglePhaseNotification? singlePhaseNotifications,
             Transaction atomicTransaction,
             EnlistmentOptions enlistmentOptions)
         {
index e1a6f78..b9256f2 100644 (file)
@@ -12,10 +12,10 @@ namespace System.Transactions
     {
         internal abstract void EnterState(InternalEnlistment enlistment);
 
-        internal static EnlistmentStatePromoted _enlistmentStatePromoted;
+        internal static EnlistmentStatePromoted? _enlistmentStatePromoted;
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
 
         internal static EnlistmentStatePromoted EnlistmentStatePromoted =>
             LazyInitializer.EnsureInitialized(ref _enlistmentStatePromoted, ref s_classSyncObject, () => new EnlistmentStatePromoted());
@@ -30,7 +30,7 @@ namespace System.Transactions
             throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId);
         }
 
-        internal virtual void ForceRollback(InternalEnlistment enlistment, Exception e)
+        internal virtual void ForceRollback(InternalEnlistment enlistment, Exception? e)
         {
             throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId);
         }
@@ -40,12 +40,12 @@ namespace System.Transactions
             throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId);
         }
 
-        internal virtual void Aborted(InternalEnlistment enlistment, Exception e)
+        internal virtual void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId);
         }
 
-        internal virtual void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal virtual void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             throw TransactionException.CreateEnlistmentStateException(null, enlistment == null ? Guid.Empty : enlistment.DistributedTxId);
         }
@@ -116,6 +116,7 @@ namespace System.Transactions
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.EnlistmentDone();
             }
             finally
@@ -129,6 +130,7 @@ namespace System.Transactions
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.Prepared();
             }
             finally
@@ -137,11 +139,12 @@ namespace System.Transactions
             }
         }
 
-        internal override void ForceRollback(InternalEnlistment enlistment, Exception e)
+        internal override void ForceRollback(InternalEnlistment enlistment, Exception? e)
         {
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.ForceRollback(e);
             }
             finally
@@ -155,6 +158,7 @@ namespace System.Transactions
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.Committed();
             }
             finally
@@ -163,11 +167,12 @@ namespace System.Transactions
             }
         }
 
-        internal override void Aborted(InternalEnlistment enlistment, Exception e)
+        internal override void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.Aborted(e);
             }
             finally
@@ -176,11 +181,12 @@ namespace System.Transactions
             }
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 enlistment.PromotedEnlistment.InDoubt(e);
             }
             finally
@@ -194,6 +200,7 @@ namespace System.Transactions
             Monitor.Exit(enlistment.SyncRoot);
             try
             {
+                Debug.Assert(enlistment.PromotedEnlistment != null);
                 return enlistment.PromotedEnlistment.GetRecoveryInformation();
             }
             finally
index c5b6410..0570040 100644 (file)
@@ -47,7 +47,7 @@ namespace System.Transactions
 
         public override int GetHashCode() => base.GetHashCode();  // Don't have anything better to do.
 
-        public override bool Equals(object obj) => obj is EnlistmentTraceIdentifier && Equals((EnlistmentTraceIdentifier)obj);
+        public override bool Equals(object? obj) => obj is EnlistmentTraceIdentifier enlistmentTraceId && Equals(enlistmentTraceId);
 
         public bool Equals(EnlistmentTraceIdentifier other) =>
             _enlistmentIdentifier == other._enlistmentIdentifier &&
index 637ec20..3e04af4 100644 (file)
@@ -16,7 +16,7 @@ namespace System.Transactions
             }
         }
 
-        internal static Transaction GetContextTransaction(ContextData contextData)
+        internal static Transaction? GetContextTransaction(ContextData contextData)
         {
             if (EnterpriseServicesOk)
             {
@@ -30,7 +30,7 @@ namespace System.Transactions
 
         internal static bool UseServiceDomainForCurrent() => false;
 
-        internal static void PushServiceDomain(Transaction newCurrent)
+        internal static void PushServiceDomain(Transaction? newCurrent)
         {
             ThrowNotSupported();
         }
index 6b385bf..8071fac 100644 (file)
@@ -17,9 +17,9 @@ namespace System.Transactions
     {
         // This variable manages the state of the transaction it should be one of the
         // static elements of TransactionState derived from TransactionState.
-        protected TransactionState _transactionState;
+        protected TransactionState? _transactionState;
 
-        internal TransactionState State
+        internal TransactionState? State
         {
             get { return _transactionState; }
             set { _transactionState = value; }
@@ -39,7 +39,7 @@ namespace System.Transactions
         // The promoted token for the transaction.
         // This is set when the transaction is promoted. For an MSDTC transaction, it is the
         // same as the DTC propagation token.
-        internal byte[] promotedToken;
+        internal byte[]? promotedToken;
 
         // This is only used if the promoter type is different than TransactionInterop.PromoterTypeDtc.
         // The promoter is supposed to tell us what the distributed transaction id after promoting it.
@@ -54,7 +54,7 @@ namespace System.Transactions
 #endif
 
         // Finalized object see class definition for the use of this object
-        internal FinalizedObject _finalizedObject;
+        internal FinalizedObject? _finalizedObject;
 
         internal readonly int _transactionHash;
         internal int TransactionHash => _transactionHash;
@@ -84,7 +84,7 @@ namespace System.Transactions
         // operation repeatedly for a given type of transaction.  So if a transaction of a specific
         // type continually causes the array size to be increased the LTM could start
         // allocating a larger array initially for transactions of that type.
-        internal InternalEnlistment _durableEnlistment;
+        internal InternalEnlistment? _durableEnlistment;
         internal VolatileEnlistmentSet _phase0Volatiles;
         internal VolatileEnlistmentSet _phase1Volatiles;
 
@@ -94,7 +94,7 @@ namespace System.Transactions
         // These members are used for promoted waves of dependent blocking clones.  The Ltm
         // does not register individually for each blocking clone created in phase 0.  Instead
         // it multiplexes a single phase 0 blocking clone only created after phase 0 has started.
-        internal DistributedDependentTransaction _phase0WaveDependentClone;
+        internal DistributedDependentTransaction? _phase0WaveDependentClone;
         internal int _phase0WaveDependentCloneCount;
 
         // These members are used for keeping track of aborting dependent clones if we promote
@@ -106,22 +106,22 @@ namespace System.Transactions
         // on the distributed TM takes care of checking to make sure all the aborting dependent
         // clones have completed as part of its Prepare processing.  These are used in conjunction with
         // phase1volatiles.dependentclones.
-        internal DistributedDependentTransaction _abortingDependentClone;
+        internal DistributedDependentTransaction? _abortingDependentClone;
         internal int _abortingDependentCloneCount;
 
         // When the size of the volatile enlistment array grows increase it by this amount.
         internal const int VolatileArrayIncrement = 8;
 
         // Data maintained for TransactionTable participation
-        internal Bucket _tableBucket;
+        internal Bucket? _tableBucket;
         internal int _bucketIndex;
 
         // Delegate to fire on transaction completion
-        internal TransactionCompletedEventHandler _transactionCompletedDelegate;
+        internal TransactionCompletedEventHandler? _transactionCompletedDelegate;
 
         // If this transaction get's promoted keep a reference to the promoted transaction
-        private DistributedTransaction _promotedTransaction;
-        internal DistributedTransaction PromotedTransaction
+        private DistributedTransaction? _promotedTransaction;
+        internal DistributedTransaction? PromotedTransaction
         {
             get { return _promotedTransaction; }
             set
@@ -133,7 +133,7 @@ namespace System.Transactions
 
         // If there was an exception that happened during promotion save that exception so that it
         // can be used as an inner exception to the transaciton aborted exception.
-        internal Exception _innerException = null;
+        internal Exception? _innerException = null;
 
         // Note the number of Transaction objects supported by this object
         internal int _cloneCount;
@@ -143,31 +143,31 @@ namespace System.Transactions
 
         // Double-checked locking pattern requires volatile for read/write synchronization
         // Manual Reset event for IAsyncResult support
-        internal volatile ManualResetEvent _asyncResultEvent;
+        internal volatile ManualResetEvent? _asyncResultEvent;
 
         // Store the callback and state for the caller of BeginCommit
         internal bool _asyncCommit;
-        internal AsyncCallback _asyncCallback;
-        internal object _asyncState;
+        internal AsyncCallback? _asyncCallback;
+        internal object? _asyncState;
 
         // Flag to indicate if we need to be pulsed for tx completion
         internal bool _needPulse;
 
         // Store the transaction information object
-        internal TransactionInformation _transactionInformation;
+        internal TransactionInformation? _transactionInformation;
 
         // Store a reference to the owning Committable Transaction
-        internal readonly CommittableTransaction _committableTransaction;
+        internal readonly CommittableTransaction? _committableTransaction;
 
         // Store a reference to the outcome source
         internal readonly Transaction _outcomeSource;
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
 
-        internal Guid DistributedTxId => State.get_Identifier(this);
+        internal Guid DistributedTxId => State!.get_Identifier(this);
 
-        private static string s_instanceIdentifier;
+        private static string? s_instanceIdentifier;
         internal static string InstanceIdentifier =>
             LazyInitializer.EnsureInitialized(ref s_instanceIdentifier, ref s_classSyncObject, () => Guid.NewGuid().ToString() + ":");
 
@@ -198,7 +198,7 @@ namespace System.Transactions
             }
         }
 
-        internal ITransactionPromoter _promoter;
+        internal ITransactionPromoter? _promoter;
 
         // This member is used to allow a PSPE enlistment to call Transaction.PSPEPromoteAndConvertToEnlistDurable when it is
         // asked to promote a transaction. The value is set to true in TransactionStatePSPEOperation.PSPEPromote before the
@@ -291,15 +291,17 @@ namespace System.Transactions
 
         internal static void DistributedTransactionOutcome(InternalTransaction tx, TransactionStatus status)
         {
-            FinalizedObject fo = null;
+            FinalizedObject? fo = null;
 
             lock (tx)
             {
                 if (null == tx._innerException)
                 {
+                    Debug.Assert(tx.PromotedTransaction != null);
                     tx._innerException = tx.PromotedTransaction.InnerException;
                 }
 
+                Debug.Assert(tx.State! != null);
                 switch (status)
                 {
                     case TransactionStatus.Committed:
@@ -356,6 +358,7 @@ namespace System.Transactions
                 Monitor.Exit(this); // Don't hold a lock calling user code.
                 try
                 {
+                    Debug.Assert(_committableTransaction != null);
                     _asyncCallback(_committableTransaction);
                 }
                 finally
@@ -368,7 +371,7 @@ namespace System.Transactions
         // Fire completion to anyone registered for outcome
         internal void FireCompletion()
         {
-            TransactionCompletedEventHandler eventHandlers = _transactionCompletedDelegate;
+            TransactionCompletedEventHandler? eventHandlers = _transactionCompletedDelegate;
 
             if (eventHandlers != null)
             {
@@ -429,7 +432,7 @@ namespace System.Transactions
             Hashtable promotedTransactionTable = TransactionManager.PromotedTransactionTable;
             lock (promotedTransactionTable)
             {
-                WeakReference weakRef = (WeakReference)promotedTransactionTable[_identifier];
+                WeakReference? weakRef = (WeakReference?)promotedTransactionTable[_identifier];
                 if (null != weakRef)
                 {
                     if (weakRef.Target != null)
index c3e1017..5c148c3 100644 (file)
@@ -52,7 +52,7 @@ namespace System.Transactions
             }
         }
 
-        public void ForceRollback(Exception e)
+        public void ForceRollback(Exception? e)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
index 4b831f7..412b142 100644 (file)
@@ -30,7 +30,7 @@ namespace System.Transactions
             }
         }
 
-        public void Aborted(Exception e)
+        public void Aborted(Exception? e)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -97,7 +97,7 @@ namespace System.Transactions
         }
 
 
-        public void InDoubt(Exception e)
+        public void InDoubt(Exception? e)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
index 38e1085..66b94ca 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Diagnostics;
+using System.Diagnostics.CodeAnalysis;
 using System.Runtime.CompilerServices;
 using System.Runtime.Serialization;
 using System.Threading;
@@ -12,11 +13,11 @@ namespace System.Transactions
 {
     public class TransactionEventArgs : EventArgs
     {
-        internal Transaction _transaction;
-        public Transaction Transaction => _transaction;
+        internal Transaction? _transaction;
+        public Transaction? Transaction => _transaction;
     }
 
-    public delegate void TransactionCompletedEventHandler(object sender, TransactionEventArgs e);
+    public delegate void TransactionCompletedEventHandler(object? sender, TransactionEventArgs e);
 
     public enum IsolationLevel
     {
@@ -67,7 +68,7 @@ namespace System.Transactions
         // This property figures out the current interop mode based on the
         // top of the transaction scope stack as well as the default mode
         // from config.
-        internal static EnterpriseServicesInteropOption InteropMode(TransactionScope currentScope)
+        internal static EnterpriseServicesInteropOption InteropMode(TransactionScope? currentScope)
         {
             if (currentScope != null)
             {
@@ -77,9 +78,9 @@ namespace System.Transactions
             return EnterpriseServicesInteropOption.None;
         }
 
-        internal static Transaction FastGetTransaction(TransactionScope currentScope, ContextData contextData, out Transaction contextTransaction)
+        internal static Transaction? FastGetTransaction(TransactionScope? currentScope, ContextData contextData, out Transaction? contextTransaction)
         {
-            Transaction current = null;
+            Transaction? current = null;
             contextTransaction = null;
 
             contextTransaction = contextData.CurrentTransaction;
@@ -97,7 +98,7 @@ namespace System.Transactions
                         // Otherwise check for an external current.
                         if (TransactionManager.s_currentDelegateSet)
                         {
-                            current = TransactionManager.s_currentDelegate();
+                            current = TransactionManager.s_currentDelegate!();
                         }
                         else
                         {
@@ -132,9 +133,9 @@ namespace System.Transactions
         // in TransactionScope because it is required to get both of them in several cases.
         internal static void GetCurrentTransactionAndScope(
             TxLookup defaultLookup,
-            out Transaction current,
-            out TransactionScope currentScope,
-            out Transaction contextTransaction)
+            out Transaction? current,
+            out TransactionScope? currentScope,
+            out Transaction? contextTransaction)
         {
             current = null;
             currentScope = null;
@@ -148,7 +149,7 @@ namespace System.Transactions
             }
         }
 
-        public static Transaction Current
+        public static Transaction? Current
         {
             get
             {
@@ -158,10 +159,7 @@ namespace System.Transactions
                     etwLog.MethodEnter(TraceSourceType.TraceSourceBase, "Transaction.get_Current");
                 }
 
-                Transaction current = null;
-                TransactionScope currentScope = null;
-                Transaction contextValue = null;
-                GetCurrentTransactionAndScope(TxLookup.Default, out current, out currentScope, out contextValue);
+                GetCurrentTransactionAndScope(TxLookup.Default, out Transaction? current, out TransactionScope? currentScope, out Transaction? contextValue);
 
                 if (currentScope != null)
                 {
@@ -242,7 +240,7 @@ namespace System.Transactions
         // Internal synchronization object for transactions.  It is not safe to lock on the
         // transaction object because it is public and users of the object may lock it for
         // other purposes.
-        internal InternalTransaction _internalTransaction;
+        internal InternalTransaction _internalTransaction = null!;
 
         // The TransactionTraceIdentifier for the transaction instance.
         internal TransactionTraceIdentifier _traceIdentifier;
@@ -252,7 +250,7 @@ namespace System.Transactions
 
         // Create a transaction with the given settings
         //
-        internal Transaction(IsolationLevel isoLevel, InternalTransaction internalTransaction)
+        internal Transaction(IsolationLevel isoLevel, InternalTransaction? internalTransaction)
         {
             TransactionManager.ValidateIsolationLevel(isoLevel);
 
@@ -319,37 +317,29 @@ namespace System.Transactions
 
         // Don't allow equals to get the identifier
         //
-        public override bool Equals(object obj)
+        public override bool Equals(object? obj)
         {
-            Transaction transaction = obj as Transaction;
-
             // If we can't cast the object as a Transaction, it must not be equal
-            // to this, which is a Transaction.
-            if (null == transaction)
-            {
-                return false;
-            }
-
-            // Check the internal transaction object for equality.
-            return _internalTransaction.TransactionHash == transaction._internalTransaction.TransactionHash;
+            // to this, which is a Transaction. Check the internal transaction object for equality.
+            return obj is Transaction transaction && _internalTransaction.TransactionHash == transaction._internalTransaction.TransactionHash;
         }
 
-        public static bool operator ==(Transaction x, Transaction y)
+        public static bool operator ==(Transaction? x, Transaction? y)
         {
-            if (((object)x) != null)
+            if (((object?)x) != null)
             {
                 return x.Equals(y);
             }
-            return ((object)y) == null;
+            return ((object?)y) == null;
         }
 
-        public static bool operator !=(Transaction x, Transaction y)
+        public static bool operator !=(Transaction? x, Transaction? y)
         {
-            if (((object)x) != null)
+            if (((object?)x) != null)
             {
                 return !x.Equals(y);
             }
-            return ((object)y) != null;
+            return ((object?)y) != null;
         }
 
 
@@ -370,7 +360,7 @@ namespace System.Transactions
                     throw new ObjectDisposedException(nameof(Transaction));
                 }
 
-                TransactionInformation txInfo = _internalTransaction._transactionInformation;
+                TransactionInformation? txInfo = _internalTransaction._transactionInformation;
                 if (txInfo == null)
                 {
                     // A race would only result in an extra allocation
@@ -483,6 +473,7 @@ namespace System.Transactions
             byte[] internalPromotedToken;
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 internalPromotedToken = _internalTransaction.State.PromotedToken(_internalTransaction);
             }
 
@@ -529,6 +520,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 Enlistment enlistment = _internalTransaction.State.EnlistDurable(_internalTransaction,
                     resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, this);
 
@@ -582,6 +574,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 Enlistment enlistment = _internalTransaction.State.EnlistDurable(_internalTransaction,
                     resourceManagerIdentifier, singlePhaseNotification, enlistmentOptions, this);
 
@@ -621,7 +614,7 @@ namespace System.Transactions
         }
 
 
-        public void Rollback(Exception e)
+        public void Rollback(Exception? e)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -680,6 +673,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 Enlistment enlistment = _internalTransaction.State.EnlistVolatile(_internalTransaction,
                     enlistmentNotification, enlistmentOptions, this);
 
@@ -724,6 +718,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 Enlistment enlistment = _internalTransaction.State.EnlistVolatile(_internalTransaction,
                     singlePhaseNotification, enlistmentOptions, this);
 
@@ -842,7 +837,7 @@ namespace System.Transactions
 
         // Forward request to the state machine to take the appropriate action.
         //
-        public event TransactionCompletedEventHandler TransactionCompleted
+        public event TransactionCompletedEventHandler? TransactionCompleted
         {
             add
             {
@@ -853,6 +848,7 @@ namespace System.Transactions
 
                 lock (_internalTransaction)
                 {
+                    Debug.Assert(_internalTransaction.State != null);
                     // Register for completion with the inner transaction
                     _internalTransaction.State.AddOutcomeRegistrant(_internalTransaction, value);
                 }
@@ -862,7 +858,7 @@ namespace System.Transactions
             {
                 lock (_internalTransaction)
                 {
-                    _internalTransaction._transactionCompletedDelegate = (TransactionCompletedEventHandler)
+                    _internalTransaction._transactionCompletedDelegate = (TransactionCompletedEventHandler?)
                         System.Delegate.Remove(_internalTransaction._transactionCompletedDelegate, value);
                 }
             }
@@ -1012,6 +1008,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 succeeded = _internalTransaction.State.EnlistPromotableSinglePhase(_internalTransaction, promotableSinglePhaseNotification, this, promoterType);
             }
 
@@ -1066,6 +1063,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 Enlistment enlistment = _internalTransaction.State.PromoteAndEnlistDurable(_internalTransaction,
                     resourceManagerIdentifier, promotableNotification, enlistmentNotification, enlistmentOptions, this);
 
@@ -1109,6 +1107,7 @@ namespace System.Transactions
 
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 _internalTransaction.State.SetDistributedTransactionId(_internalTransaction,
                     promotableNotification,
                     distributedTransactionIdentifier);
@@ -1121,10 +1120,11 @@ namespace System.Transactions
             }
         }
 
-        internal DistributedTransaction Promote()
+        internal DistributedTransaction? Promote()
         {
             lock (_internalTransaction)
             {
+                Debug.Assert(_internalTransaction.State != null);
                 // This method is only called when we expect to be promoting to MSDTC.
                 _internalTransaction.ThrowIfPromoterTypeIsNotMSDTC();
                 _internalTransaction.State.Promote(_internalTransaction);
@@ -1166,7 +1166,7 @@ namespace System.Transactions
     //
     internal static class CallContextCurrentData
     {
-        private static readonly AsyncLocal<ContextKey> s_currentTransaction = new AsyncLocal<ContextKey>();
+        private static readonly AsyncLocal<ContextKey?> s_currentTransaction = new AsyncLocal<ContextKey?>();
 
         // ConditionalWeakTable is used to automatically remove the entries that are no longer referenced. This will help prevent leaks in async nested TransactionScope
         // usage and when child nested scopes are not syncronized properly.
@@ -1182,17 +1182,17 @@ namespace System.Transactions
             return s_contextDataTable.GetValue(contextKey, (env) => new ContextData(true));
         }
 
-        public static void ClearCurrentData(ContextKey contextKey, bool removeContextData)
+        public static void ClearCurrentData(ContextKey? contextKey, bool removeContextData)
         {
             // Get the current ambient CallContext.
-            ContextKey key = s_currentTransaction.Value;
+            ContextKey? key = s_currentTransaction.Value;
             if (contextKey != null || key != null)
             {
                 // removeContextData flag is used for perf optimization to avoid removing from the table in certain nested TransactionScope usage.
                 if (removeContextData)
                 {
                     // if context key is passed in remove that from the contextDataTable, otherwise remove the default context key.
-                    s_contextDataTable.Remove(contextKey ?? key);
+                    s_contextDataTable.Remove(contextKey ?? key!);
                 }
 
                 if (key != null)
@@ -1202,10 +1202,10 @@ namespace System.Transactions
             }
         }
 
-        public static bool TryGetCurrentData(out ContextData currentData)
+        public static bool TryGetCurrentData([NotNullWhen(true)] out ContextData? currentData)
         {
             currentData = null;
-            ContextKey contextKey = s_currentTransaction.Value;
+            ContextKey? contextKey = s_currentTransaction.Value;
             if (contextKey == null)
             {
                 return false;
@@ -1226,27 +1226,28 @@ namespace System.Transactions
 
     internal class ContextData
     {
-        internal TransactionScope CurrentScope;
-        internal Transaction CurrentTransaction;
+        internal TransactionScope? CurrentScope;
+        internal Transaction? CurrentTransaction;
 
         internal DefaultComContextState DefaultComContextState;
-        internal WeakReference WeakDefaultComContext;
+        internal WeakReference? WeakDefaultComContext;
 
         internal bool _asyncFlow;
 
         [ThreadStatic]
-        private static ContextData t_staticData;
+        private static ContextData? t_staticData;
 
         internal ContextData(bool asyncFlow)
         {
             _asyncFlow = asyncFlow;
         }
 
+        [AllowNull]
         internal static ContextData TLSCurrentData
         {
             get
             {
-                ContextData data = t_staticData;
+                ContextData? data = t_staticData;
                 if (data == null)
                 {
                     data = new ContextData(false);
@@ -1274,7 +1275,7 @@ namespace System.Transactions
 
         internal static ContextData LookupContextData(TxLookup defaultLookup)
         {
-            ContextData currentData = null;
+            ContextData? currentData = null;
             if (CallContextCurrentData.TryGetCurrentData(out currentData))
             {
                 if (currentData.CurrentScope == null && currentData.CurrentTransaction == null && defaultLookup != TxLookup.DefaultCallContext)
index 469a1a2..b88fdd4 100644 (file)
@@ -19,7 +19,7 @@ namespace System.Transactions
             return (distributedTxId != Guid.Empty && AppSettings.IncludeDistributedTxIdInExceptionMessage);
         }
 
-        internal static TransactionException Create(string message, Exception innerException)
+        internal static TransactionException Create(string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -30,7 +30,7 @@ namespace System.Transactions
             return new TransactionException(message, innerException);
         }
 
-        internal static TransactionException Create(TraceSourceType traceSource, string message, Exception innerException)
+        internal static TransactionException Create(TraceSourceType traceSource, string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -40,12 +40,12 @@ namespace System.Transactions
 
             return new TransactionException(message, innerException);
         }
-        internal static TransactionException CreateTransactionStateException(Exception innerException)
+        internal static TransactionException CreateTransactionStateException(Exception? innerException)
         {
             return Create(SR.TransactionStateException, innerException);
         }
 
-        internal static Exception CreateEnlistmentStateException(Exception innerException, Guid distributedTxId)
+        internal static Exception CreateEnlistmentStateException(Exception? innerException, Guid distributedTxId)
         {
             string messagewithTxId = SR.EnlistmentStateException;
             if (IncludeDistributedTxId(distributedTxId))
@@ -59,7 +59,7 @@ namespace System.Transactions
             return new InvalidOperationException(messagewithTxId, innerException);
         }
 
-        internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string message, Exception innerException)
+        internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -81,7 +81,7 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="message"></param>
-        public TransactionException(string message) : base(message)
+        public TransactionException(string? message) : base(message)
         {
         }
 
@@ -90,7 +90,7 @@ namespace System.Transactions
         /// </summary>
         /// <param name="message"></param>
         /// <param name="innerException"></param>
-        public TransactionException(string message, Exception innerException) : base(message, innerException)
+        public TransactionException(string? message, Exception? innerException) : base(message, innerException)
         {
         }
 
@@ -103,7 +103,7 @@ namespace System.Transactions
         {
         }
 
-        internal static TransactionException Create(string message, Guid distributedTxId)
+        internal static TransactionException Create(string? message, Guid distributedTxId)
         {
             if (IncludeDistributedTxId(distributedTxId))
             {
@@ -112,25 +112,25 @@ namespace System.Transactions
             return new TransactionException(message);
         }
 
-        internal static TransactionException Create(string message, Exception innerException, Guid distributedTxId)
+        internal static TransactionException Create(string? message, Exception? innerException, Guid distributedTxId)
         {
-            string messagewithTxId = message;
+            string? messagewithTxId = message;
             if (IncludeDistributedTxId(distributedTxId))
                 messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId);
 
             return Create(messagewithTxId, innerException);
         }
 
-        internal static TransactionException Create(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId)
+        internal static TransactionException Create(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId)
         {
-            string messagewithTxId = message;
+            string? messagewithTxId = message;
             if (IncludeDistributedTxId(distributedTxId))
                 messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId);
 
             return Create(traceSource, messagewithTxId, innerException);
         }
 
-        internal static TransactionException Create(TraceSourceType traceSource, string message, Guid distributedTxId)
+        internal static TransactionException Create(TraceSourceType traceSource, string? message, Guid distributedTxId)
         {
             if (IncludeDistributedTxId(distributedTxId))
             {
@@ -139,7 +139,7 @@ namespace System.Transactions
             return new TransactionException(message);
         }
 
-        internal static TransactionException CreateTransactionStateException(Exception innerException, Guid distributedTxId)
+        internal static TransactionException CreateTransactionStateException(Exception? innerException, Guid distributedTxId)
         {
             return Create(SR.TransactionStateException, innerException, distributedTxId);
         }
@@ -159,9 +159,9 @@ namespace System.Transactions
             return new InvalidOperationException(messagewithTxId);
         }
 
-        internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId)
+        internal static Exception CreateInvalidOperationException(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId)
         {
-            string messagewithTxId = message;
+            string? messagewithTxId = message;
             if (IncludeDistributedTxId(distributedTxId))
                 messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId);
 
@@ -177,16 +177,16 @@ namespace System.Transactions
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public class TransactionAbortedException : TransactionException
     {
-        internal static new TransactionAbortedException Create(string message, Exception innerException, Guid distributedTxId)
+        internal static new TransactionAbortedException Create(string? message, Exception? innerException, Guid distributedTxId)
         {
-            string messagewithTxId = message;
+            string? messagewithTxId = message;
             if (IncludeDistributedTxId(distributedTxId))
                 messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId);
 
             return TransactionAbortedException.Create(messagewithTxId, innerException);
         }
 
-        internal static new TransactionAbortedException Create(string message, Exception innerException)
+        internal static new TransactionAbortedException Create(string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -207,7 +207,7 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="message"></param>
-        public TransactionAbortedException(string message) : base(message)
+        public TransactionAbortedException(string? message) : base(message)
         {
         }
 
@@ -216,7 +216,7 @@ namespace System.Transactions
         /// </summary>
         /// <param name="message"></param>
         /// <param name="innerException"></param>
-        public TransactionAbortedException(string message, Exception innerException) : base(message, innerException)
+        public TransactionAbortedException(string? message, Exception? innerException) : base(message, innerException)
         {
         }
 
@@ -224,11 +224,11 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="innerException"></param>
-        internal TransactionAbortedException(Exception innerException) : base(SR.TransactionAborted, innerException)
+        internal TransactionAbortedException(Exception? innerException) : base(SR.TransactionAborted, innerException)
         {
         }
 
-        internal TransactionAbortedException(Exception innerException, Guid distributedTxId) :
+        internal TransactionAbortedException(Exception? innerException, Guid distributedTxId) :
             base(IncludeDistributedTxId(distributedTxId) ?
                 SR.Format(SR.DistributedTxIDInTransactionException, SR.TransactionAborted, distributedTxId)
                 : SR.TransactionAborted, innerException)
@@ -252,16 +252,16 @@ namespace System.Transactions
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public class TransactionInDoubtException : TransactionException
     {
-        internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string message, Exception innerException, Guid distributedTxId)
+        internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string? message, Exception? innerException, Guid distributedTxId)
         {
-            string messagewithTxId = message;
+            string? messagewithTxId = message;
             if (IncludeDistributedTxId(distributedTxId))
                 messagewithTxId = SR.Format(SR.DistributedTxIDInTransactionException, messagewithTxId, distributedTxId);
 
             return TransactionInDoubtException.Create(traceSource, messagewithTxId, innerException);
         }
 
-        internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string message, Exception innerException)
+        internal static new TransactionInDoubtException Create(TraceSourceType traceSource, string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -283,7 +283,7 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="message"></param>
-        public TransactionInDoubtException(string message) : base(message)
+        public TransactionInDoubtException(string? message) : base(message)
         {
         }
 
@@ -292,7 +292,7 @@ namespace System.Transactions
         /// </summary>
         /// <param name="message"></param>
         /// <param name="innerException"></param>
-        public TransactionInDoubtException(string message, Exception innerException) : base(message, innerException)
+        public TransactionInDoubtException(string? message, Exception? innerException) : base(message, innerException)
         {
         }
 
@@ -313,7 +313,7 @@ namespace System.Transactions
     [System.Runtime.CompilerServices.TypeForwardedFrom("System.Transactions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")]
     public class TransactionManagerCommunicationException : TransactionException
     {
-        internal static new TransactionManagerCommunicationException Create(string message, Exception innerException)
+        internal static new TransactionManagerCommunicationException Create(string? message, Exception? innerException)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -324,7 +324,7 @@ namespace System.Transactions
             return new TransactionManagerCommunicationException(message, innerException);
         }
 
-        internal static TransactionManagerCommunicationException Create(Exception innerException)
+        internal static TransactionManagerCommunicationException Create(Exception? innerException)
         {
             return Create(SR.TransactionManagerCommunicationException, innerException);
         }
@@ -340,7 +340,7 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="message"></param>
-        public TransactionManagerCommunicationException(string message) : base(message)
+        public TransactionManagerCommunicationException(string? message) : base(message)
         {
         }
 
@@ -350,8 +350,8 @@ namespace System.Transactions
         /// <param name="message"></param>
         /// <param name="innerException"></param>
         public TransactionManagerCommunicationException(
-            string message,
-            Exception innerException
+            string? message,
+            Exception? innerException
             ) : base(message, innerException)
         {
         }
@@ -381,7 +381,7 @@ namespace System.Transactions
         ///
         /// </summary>
         /// <param name="message"></param>
-        public TransactionPromotionException(string message) : base(message)
+        public TransactionPromotionException(string? message) : base(message)
         {
         }
 
@@ -390,7 +390,7 @@ namespace System.Transactions
         /// </summary>
         /// <param name="message"></param>
         /// <param name="innerException"></param>
-        public TransactionPromotionException(string message, Exception innerException) : base(message, innerException)
+        public TransactionPromotionException(string? message, Exception? innerException) : base(message, innerException)
         {
         }
 
index 020903b..8c3ce9f 100644 (file)
@@ -2,6 +2,8 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
+
 namespace System.Transactions
 {
     public class TransactionInformation
@@ -55,6 +57,7 @@ namespace System.Transactions
 
                     lock (_internalTransaction)
                     {
+                        Debug.Assert(_internalTransaction.State != null);
                         return _internalTransaction.State.get_Identifier(_internalTransaction);
                     }
                 }
@@ -83,6 +86,7 @@ namespace System.Transactions
 
                 try
                 {
+                    Debug.Assert(_internalTransaction.State != null);
                     return _internalTransaction.State.get_Status(_internalTransaction);
                 }
                 finally
index c5e85d1..2219525 100644 (file)
@@ -38,7 +38,7 @@ namespace System.Transactions
                 throw TransactionException.CreateTransactionCompletedException(transaction.DistributedTxId);
             }
 
-            DistributedTransaction distributedTx = transaction.Promote();
+            DistributedTransaction? distributedTx = transaction.Promote();
             if (distributedTx == null)
             {
                 throw DistributedTransaction.NotSupported();
@@ -123,7 +123,7 @@ namespace System.Transactions
 
             // First check to see if there is a promoted LTM transaction with the same ID.  If there
             // is, just return that.
-            Transaction transaction = TransactionManager.FindPromotedTransaction(txId);
+            Transaction? transaction = TransactionManager.FindPromotedTransaction(txId);
             if (transaction != null)
             {
                 if (etwLog.IsEnabled())
@@ -194,7 +194,7 @@ namespace System.Transactions
             var txId = new Guid(propagationToken.AsSpan(8, 16));
 
             // First check to see if there is a promoted LTM transaction with the same ID.  If there is, just return that.
-            Transaction tx = TransactionManager.FindPromotedTransaction(txId);
+            Transaction? tx = TransactionManager.FindPromotedTransaction(txId);
             if (null != tx)
             {
                 if (etwLog.IsEnabled())
index 5c02a86..a6f3d00 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections;
+using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using System.IO;
 using System.Runtime.Serialization;
@@ -13,9 +14,9 @@ using System.Transactions.Distributed;
 
 namespace System.Transactions
 {
-    public delegate Transaction HostCurrentTransactionCallback();
+    public delegate Transaction? HostCurrentTransactionCallback();
 
-    public delegate void TransactionStartedEventHandler(object sender, TransactionEventArgs e);
+    public delegate void TransactionStartedEventHandler(object? sender, TransactionEventArgs e);
 
     public static class TransactionManager
     {
@@ -26,19 +27,19 @@ namespace System.Transactions
         // Hashtable of promoted transactions, keyed by identifier guid.  This is used by
         // FindPromotedTransaction to support transaction equivalence when a transaction is
         // serialized and then deserialized back in this app-domain.
-        private static Hashtable s_promotedTransactionTable;
+        private static Hashtable? s_promotedTransactionTable;
 
         // Sorted Table of transaction timeouts
-        private static TransactionTable s_transactionTable;
+        private static TransactionTable? s_transactionTable;
 
-        private static TransactionStartedEventHandler s_distributedTransactionStartedDelegate;
-        public static event TransactionStartedEventHandler DistributedTransactionStarted
+        private static TransactionStartedEventHandler? s_distributedTransactionStartedDelegate;
+        public static event TransactionStartedEventHandler? DistributedTransactionStarted
         {
             add
             {
                 lock (ClassSyncObject)
                 {
-                    s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Combine(s_distributedTransactionStartedDelegate, value);
+                    s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler?)System.Delegate.Combine(s_distributedTransactionStartedDelegate, value);
                     if (value != null)
                     {
                         ProcessExistingTransactions(value);
@@ -50,7 +51,7 @@ namespace System.Transactions
             {
                 lock (ClassSyncObject)
                 {
-                    s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler)System.Delegate.Remove(s_distributedTransactionStartedDelegate, value);
+                    s_distributedTransactionStartedDelegate = (TransactionStartedEventHandler?)System.Delegate.Remove(s_distributedTransactionStartedDelegate, value);
                 }
             }
         }
@@ -63,9 +64,9 @@ namespace System.Transactions
                 IDictionaryEnumerator e = PromotedTransactionTable.GetEnumerator();
                 while (e.MoveNext())
                 {
-                    WeakReference weakRef = (WeakReference)e.Value;
-                    Transaction tx = (Transaction)weakRef.Target;
-                    if (tx != null)
+                    WeakReference weakRef = (WeakReference)e.Value!;
+
+                    if (weakRef.Target is Transaction tx)
                     {
                         TransactionEventArgs args = new TransactionEventArgs();
                         args._transaction = tx.InternalClone();
@@ -77,7 +78,7 @@ namespace System.Transactions
 
         internal static void FireDistributedTransactionStarted(Transaction transaction)
         {
-            TransactionStartedEventHandler localStartedEventHandler = null;
+            TransactionStartedEventHandler? localStartedEventHandler = null;
             lock (ClassSyncObject)
             {
                 localStartedEventHandler = s_distributedTransactionStartedDelegate;
@@ -92,13 +93,14 @@ namespace System.Transactions
         }
 
         // Data storage for current delegate
-        internal static HostCurrentTransactionCallback s_currentDelegate = null;
+        internal static HostCurrentTransactionCallback? s_currentDelegate = null;
         internal static bool s_currentDelegateSet = false;
 
         // CurrentDelegate
         //
         // Store a delegate to be used to query for an external current transaction.
-        public static HostCurrentTransactionCallback HostCurrentCallback
+        [DisallowNull]
+        public static HostCurrentTransactionCallback? HostCurrentCallback
         {
             // get_HostCurrentCallback is used from get_CurrentTransaction, which doesn't have any permission requirements.
             // We don't expose what is returned from this property in that case.  But we don't want just anybody being able
@@ -161,8 +163,8 @@ namespace System.Transactions
             // Put the recovery information into a stream.
             MemoryStream stream = new MemoryStream(recoveryInformation);
             int recoveryInformationVersion = 0;
-            string nodeName = null;
-            byte[] resourceManagerRecoveryInformation = null;
+            string? nodeName = null;
+            byte[]? resourceManagerRecoveryInformation = null;
 
             try
             {
@@ -229,7 +231,7 @@ namespace System.Transactions
         }
 
 
-        private static DistributedTransactionManager CheckTransactionManager(string nodeName)
+        private static DistributedTransactionManager CheckTransactionManager(string? nodeName)
         {
             DistributedTransactionManager tm = DistributedTransactionManager;
             if (!((tm.NodeName == null && (nodeName == null || nodeName.Length == 0)) ||
@@ -264,7 +266,7 @@ namespace System.Transactions
 
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
 
         // Helper object for static synchronization
         private static object ClassSyncObject => LazyInitializer.EnsureInitialized(ref s_classSyncObject);
@@ -285,7 +287,7 @@ namespace System.Transactions
         }
 
 
-        private static DefaultSettingsSection s_defaultSettings;
+        private static DefaultSettingsSection? s_defaultSettings;
         private static DefaultSettingsSection DefaultSettings
         {
             get
@@ -300,7 +302,7 @@ namespace System.Transactions
         }
 
 
-        private static MachineSettingsSection s_machineSettings;
+        private static MachineSettingsSection? s_machineSettings;
         private static MachineSettingsSection MachineSettings
         {
             get
@@ -377,7 +379,7 @@ namespace System.Transactions
         // type of the calling object and its provided parameter collection.  This information
         // we be read back by the static Reenlist method to create the necessary transaction
         // manager object with the right parameters in order to do a ReenlistTransaction call.
-        internal static byte[] GetRecoveryInformation(string startupInfo, byte[] resourceManagerRecoveryInformation)
+        internal static byte[] GetRecoveryInformation(string? startupInfo, byte[] resourceManagerRecoveryInformation)
         {
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
@@ -386,7 +388,7 @@ namespace System.Transactions
             }
 
             MemoryStream stream = new MemoryStream();
-            byte[] returnValue = null;
+            byte[]? returnValue = null;
 
             try
             {
@@ -422,7 +424,7 @@ namespace System.Transactions
         internal static byte[] ConvertToByteArray(object thingToConvert)
         {
             MemoryStream streamToWrite = new MemoryStream();
-            byte[] returnValue = null;
+            byte[]? returnValue = null;
 
             try
             {
@@ -493,14 +495,13 @@ namespace System.Transactions
             return transactionTimeout;
         }
 
-        internal static Transaction FindPromotedTransaction(Guid transactionIdentifier)
+        internal static Transaction? FindPromotedTransaction(Guid transactionIdentifier)
         {
             Hashtable promotedTransactionTable = PromotedTransactionTable;
-            WeakReference weakRef = (WeakReference)promotedTransactionTable[transactionIdentifier];
+            WeakReference? weakRef = (WeakReference?)promotedTransactionTable[transactionIdentifier];
             if (null != weakRef)
             {
-                Transaction tx = weakRef.Target as Transaction;
-                if (null != tx)
+                if (weakRef.Target is Transaction tx)
                 {
                     return tx.InternalClone();
                 }
@@ -518,11 +519,11 @@ namespace System.Transactions
 
         internal static Transaction FindOrCreatePromotedTransaction(Guid transactionIdentifier, DistributedTransaction dtx)
         {
-            Transaction tx = null;
+            Transaction? tx = null;
             Hashtable promotedTransactionTable = PromotedTransactionTable;
             lock (promotedTransactionTable)
             {
-                WeakReference weakRef = (WeakReference)promotedTransactionTable[transactionIdentifier];
+                WeakReference? weakRef = (WeakReference?)promotedTransactionTable[transactionIdentifier];
                 if (null != weakRef)
                 {
                     tx = weakRef.Target as Transaction;
@@ -566,7 +567,7 @@ namespace System.Transactions
             LazyInitializer.EnsureInitialized(ref s_transactionTable, ref s_classSyncObject, () => new TransactionTable());
 
         // Fault in a DistributedTransactionManager if one has not already been created.
-        internal static DistributedTransactionManager distributedTransactionManager;
+        internal static DistributedTransactionManager? distributedTransactionManager;
         internal static DistributedTransactionManager DistributedTransactionManager =>
             // If the distributed transaction manager is not configured, throw an exception
             LazyInitializer.EnsureInitialized(ref distributedTransactionManager, ref s_classSyncObject, () => new DistributedTransactionManager());
index 6a964a5..7ed59f3 100644 (file)
@@ -23,7 +23,7 @@ namespace System.Transactions
 
         public override int GetHashCode() => base.GetHashCode();  // Don't have anything better to do.
 
-        public override bool Equals(object obj) => obj is TransactionOptions && Equals((TransactionOptions)obj);
+        public override bool Equals(object? obj) => obj is TransactionOptions transactionOptions && Equals(transactionOptions);
 
         private bool Equals(TransactionOptions other) =>
             _timeout == other._timeout &&
index 280ed9b..71e2285 100644 (file)
@@ -530,21 +530,22 @@ namespace System.Transactions
                 throw new InvalidOperationException(SR.InvalidScopeThread);
             }
 
-            Exception exToThrow = null;
+            Exception? exToThrow = null;
 
             try
             {
                 // Single threaded from this point
                 _disposed = true;
 
+                Debug.Assert(_threadContextData != null);
                 // First, lets pop the "stack" of TransactionScopes and dispose each one that is above us in
                 // the stack, making sure they are NOT consistent before disposing them.
 
                 // Optimize the first lookup by getting both the actual current scope and actual current
                 // transaction at the same time.
-                TransactionScope actualCurrentScope = _threadContextData.CurrentScope;
-                Transaction contextTransaction = null;
-                Transaction current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction);
+                TransactionScope? actualCurrentScope = _threadContextData.CurrentScope;
+                Transaction? contextTransaction = null;
+                Transaction? current = Transaction.FastGetTransaction(actualCurrentScope, _threadContextData, out contextTransaction);
 
                 if (!Equals(actualCurrentScope))
                 {
@@ -556,7 +557,7 @@ namespace System.Transactions
                         // Something must have gone wrong trying to clean up a bad scope
                         // stack previously.
                         // Make a best effort to abort the active transaction.
-                        Transaction rollbackTransaction = _committableTransaction;
+                        Transaction? rollbackTransaction = _committableTransaction;
                         if (rollbackTransaction == null)
                         {
                             rollbackTransaction = _dependentTransaction;
@@ -633,7 +634,7 @@ namespace System.Transactions
                                 current == null ? Guid.Empty : current.DistributedTxId);
                         }
 
-                        if (null == actualCurrentScope._expectedCurrent)
+                        if (null == actualCurrentScope!._expectedCurrent)
                         {
                             if (etwLog.IsEnabled())
                             {
@@ -793,7 +794,7 @@ namespace System.Transactions
                         // Note: Rollback is not called on expected current because someone could conceiveably
                         //       dispose expectedCurrent out from under the transaction scope.
                         //
-                        Transaction rollbackTransaction = _committableTransaction;
+                        Transaction? rollbackTransaction = _committableTransaction;
                         if (rollbackTransaction == null)
                         {
                             rollbackTransaction = _dependentTransaction;
@@ -827,6 +828,7 @@ namespace System.Transactions
                 {
                     _committableTransaction.Dispose();
 
+                    Debug.Assert(_expectedCurrent != null);
                     // If we created the committable transaction then we placed a clone in expectedCurrent
                     // and it needs to be disposed as well.
                     _expectedCurrent.Dispose();
@@ -863,9 +865,9 @@ namespace System.Transactions
             }
         }
 
-        private static void TimerCallback(object state)
+        private static void TimerCallback(object? state)
         {
-            TransactionScope scope = state as TransactionScope;
+            TransactionScope? scope = state as TransactionScope;
             if (null == scope)
             {
                 TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
@@ -952,6 +954,7 @@ namespace System.Transactions
 
             if (AsyncFlowEnabled)
             {
+                Debug.Assert(ContextKey != null);
                 // Async Flow is enabled and CallContext will be used for ambient transaction.
                 _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(ContextKey);
 
@@ -998,6 +1001,7 @@ namespace System.Transactions
             {
                 if (_savedCurrentScope.AsyncFlowEnabled)
                 {
+                    Debug.Assert(_savedCurrentScope.ContextKey != null);
                     _threadContextData = CallContextCurrentData.CreateOrGetCurrentData(_savedCurrentScope.ContextKey);
                 }
                 else
@@ -1039,6 +1043,7 @@ namespace System.Transactions
             // prevent restoring the context in an unexpected thread due to thread switch during TransactionScope's Dispose
             if (shouldRestoreContextData)
             {
+                Debug.Assert(_threadContextData != null);
                 _threadContextData.CurrentScope = _savedCurrentScope;
                 RestoreCurrent();
             }
@@ -1047,7 +1052,7 @@ namespace System.Transactions
         // SetCurrent
         //
         // Place the given value in current by whatever means necessary for interop mode.
-        private void SetCurrent(Transaction newCurrent)
+        private void SetCurrent(Transaction? newCurrent)
         {
             // Keep a dependent clone of current if we don't have one and we are not committable
             if (_dependentTransaction == null && _committableTransaction == null)
@@ -1061,7 +1066,7 @@ namespace System.Transactions
             switch (_interopOption)
             {
                 case EnterpriseServicesInteropOption.None:
-                    _threadContextData.CurrentTransaction = newCurrent;
+                    _threadContextData!.CurrentTransaction = newCurrent;
                     break;
 
                 case EnterpriseServicesInteropOption.Automatic:
@@ -1072,7 +1077,7 @@ namespace System.Transactions
                     }
                     else
                     {
-                        _threadContextData.CurrentTransaction = newCurrent;
+                        _threadContextData!.CurrentTransaction = newCurrent;
                     }
                     break;
 
@@ -1118,7 +1123,7 @@ namespace System.Transactions
             }
 
             // Only restore the value that was actually in the context.
-            _threadContextData.CurrentTransaction = _contextTransaction;
+            _threadContextData!.CurrentTransaction = _contextTransaction;
         }
 
 
@@ -1137,7 +1142,7 @@ namespace System.Transactions
         // ValidateScopeTimeout
         //
         // Scope timeouts are not governed by MaxTimeout and therefore need a special validate function
-        private void ValidateScopeTimeout(string paramName, TimeSpan scopeTimeout)
+        private void ValidateScopeTimeout(string? paramName, TimeSpan scopeTimeout)
         {
             if (scopeTimeout < TimeSpan.Zero)
             {
@@ -1189,41 +1194,41 @@ namespace System.Transactions
         }
 
         // Storage location for the previous current transaction.
-        private Transaction _savedCurrent;
+        private Transaction? _savedCurrent;
 
         // To ensure that we don't restore a value for current that was
         // returned to us by an external entity keep the value that was actually
         // in TLS when the scope was created.
-        private Transaction _contextTransaction;
+        private Transaction? _contextTransaction;
 
         // Storage for the value to restore to current
-        private TransactionScope _savedCurrentScope;
+        private TransactionScope? _savedCurrentScope;
 
         // Store a reference to the context data object for this scope.
-        private ContextData _threadContextData;
+        private ContextData? _threadContextData;
 
-        private ContextData _savedTLSContextData;
+        private ContextData? _savedTLSContextData;
 
         // Store a reference to the value that this scope expects for current
-        private Transaction _expectedCurrent;
+        private Transaction? _expectedCurrent;
 
         // Store a reference to the committable form of this transaction if
         // the scope made one.
-        private CommittableTransaction _committableTransaction;
+        private CommittableTransaction? _committableTransaction;
 
         // Store a reference to the scopes transaction guard.
-        private DependentTransaction _dependentTransaction;
+        private DependentTransaction? _dependentTransaction;
 
         // Note when the scope is disposed.
         private bool _disposed;
 
         // BUGBUG: A shared timer should be used.
         // Individual timer for this scope.
-        private Timer _scopeTimer;
+        private Timer? _scopeTimer;
 
         // Store a reference to the thread on which the scope was created so that we can
         // check to make sure that the dispose pattern for scope is being used correctly.
-        private Thread _scopeThread;
+        private Thread? _scopeThread;
 
         // Store the interop mode for this transaction scope.
         private bool _interopModeSpecified = false;
@@ -1236,7 +1241,7 @@ namespace System.Transactions
             }
         }
 
-        internal ContextKey ContextKey
+        internal ContextKey? ContextKey
         {
             get;
             private set;
index 2d911c0..cb49abc 100644 (file)
@@ -20,45 +20,45 @@ namespace System.Transactions
         // The state machines themselves are designed to be internally consistent.  So the only externally visable
         // state transition is to active.  All other state transitions must happen within the state machines
         // themselves.
-        private static TransactionStateActive s_transactionStateActive;
-        private static TransactionStateSubordinateActive s_transactionStateSubordinateActive;
-        private static TransactionStatePhase0 s_transactionStatePhase0;
-        private static TransactionStateVolatilePhase1 s_transactionStateVolatilePhase1;
-        private static TransactionStateVolatileSPC s_transactionStateVolatileSPC;
-        private static TransactionStateSPC s_transactionStateSPC;
-        private static TransactionStateAborted s_transactionStateAborted;
-        private static TransactionStateCommitted s_transactionStateCommitted;
-        private static TransactionStateInDoubt s_transactionStateInDoubt;
-
-        private static TransactionStatePromoted s_transactionStatePromoted;
-        private static TransactionStateNonCommittablePromoted s_transactionStateNonCommittablePromoted;
-        private static TransactionStatePromotedP0Wave s_transactionStatePromotedP0Wave;
-        private static TransactionStatePromotedCommitting s_transactionStatePromotedCommitting;
-        private static TransactionStatePromotedPhase0 s_transactionStatePromotedPhase0;
-        private static TransactionStatePromotedPhase1 s_transactionStatePromotedPhase1;
-        private static TransactionStatePromotedP0Aborting s_transactionStatePromotedP0Aborting;
-        private static TransactionStatePromotedP1Aborting s_transactionStatePromotedP1Aborting;
-        private static TransactionStatePromotedAborted s_transactionStatePromotedAborted;
-        private static TransactionStatePromotedCommitted s_transactionStatePromotedCommitted;
-        private static TransactionStatePromotedIndoubt s_transactionStatePromotedIndoubt;
-
-        private static TransactionStateDelegated s_transactionStateDelegated;
-        private static TransactionStateDelegatedSubordinate s_transactionStateDelegatedSubordinate;
-        private static TransactionStateDelegatedP0Wave s_transactionStateDelegatedP0Wave;
-        private static TransactionStateDelegatedCommitting s_transactionStateDelegatedCommitting;
-        private static TransactionStateDelegatedAborting s_transactionStateDelegatedAborting;
-        private static TransactionStatePSPEOperation s_transactionStatePSPEOperation;
-
-        private static TransactionStateDelegatedNonMSDTC s_transactionStateDelegatedNonMSDTC;
-        private static TransactionStatePromotedNonMSDTCPhase0 s_transactionStatePromotedNonMSDTCPhase0;
-        private static TransactionStatePromotedNonMSDTCVolatilePhase1 s_transactionStatePromotedNonMSDTCVolatilePhase1;
-        private static TransactionStatePromotedNonMSDTCSinglePhaseCommit s_transactionStatePromotedNonMSDTCSinglePhaseCommit;
-        private static TransactionStatePromotedNonMSDTCAborted s_transactionStatePromotedNonMSDTCAborted;
-        private static TransactionStatePromotedNonMSDTCCommitted s_transactionStatePromotedNonMSDTCCommitted;
-        private static TransactionStatePromotedNonMSDTCIndoubt s_transactionStatePromotedNonMSDTCIndoubt;
+        private static TransactionStateActive? s_transactionStateActive;
+        private static TransactionStateSubordinateActive? s_transactionStateSubordinateActive;
+        private static TransactionStatePhase0? s_transactionStatePhase0;
+        private static TransactionStateVolatilePhase1? s_transactionStateVolatilePhase1;
+        private static TransactionStateVolatileSPC? s_transactionStateVolatileSPC;
+        private static TransactionStateSPC? s_transactionStateSPC;
+        private static TransactionStateAborted? s_transactionStateAborted;
+        private static TransactionStateCommitted? s_transactionStateCommitted;
+        private static TransactionStateInDoubt? s_transactionStateInDoubt;
+
+        private static TransactionStatePromoted? s_transactionStatePromoted;
+        private static TransactionStateNonCommittablePromoted? s_transactionStateNonCommittablePromoted;
+        private static TransactionStatePromotedP0Wave? s_transactionStatePromotedP0Wave;
+        private static TransactionStatePromotedCommitting? s_transactionStatePromotedCommitting;
+        private static TransactionStatePromotedPhase0? s_transactionStatePromotedPhase0;
+        private static TransactionStatePromotedPhase1? s_transactionStatePromotedPhase1;
+        private static TransactionStatePromotedP0Aborting? s_transactionStatePromotedP0Aborting;
+        private static TransactionStatePromotedP1Aborting? s_transactionStatePromotedP1Aborting;
+        private static TransactionStatePromotedAborted? s_transactionStatePromotedAborted;
+        private static TransactionStatePromotedCommitted? s_transactionStatePromotedCommitted;
+        private static TransactionStatePromotedIndoubt? s_transactionStatePromotedIndoubt;
+
+        private static TransactionStateDelegated? s_transactionStateDelegated;
+        private static TransactionStateDelegatedSubordinate? s_transactionStateDelegatedSubordinate;
+        private static TransactionStateDelegatedP0Wave? s_transactionStateDelegatedP0Wave;
+        private static TransactionStateDelegatedCommitting? s_transactionStateDelegatedCommitting;
+        private static TransactionStateDelegatedAborting? s_transactionStateDelegatedAborting;
+        private static TransactionStatePSPEOperation? s_transactionStatePSPEOperation;
+
+        private static TransactionStateDelegatedNonMSDTC? s_transactionStateDelegatedNonMSDTC;
+        private static TransactionStatePromotedNonMSDTCPhase0? s_transactionStatePromotedNonMSDTCPhase0;
+        private static TransactionStatePromotedNonMSDTCVolatilePhase1? s_transactionStatePromotedNonMSDTCVolatilePhase1;
+        private static TransactionStatePromotedNonMSDTCSinglePhaseCommit? s_transactionStatePromotedNonMSDTCSinglePhaseCommit;
+        private static TransactionStatePromotedNonMSDTCAborted? s_transactionStatePromotedNonMSDTCAborted;
+        private static TransactionStatePromotedNonMSDTCCommitted? s_transactionStatePromotedNonMSDTCCommitted;
+        private static TransactionStatePromotedNonMSDTCIndoubt? s_transactionStatePromotedNonMSDTCIndoubt;
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        internal static object s_classSyncObject;
+        internal static object? s_classSyncObject;
 
         internal static TransactionStateActive TransactionStateActive =>
             LazyInitializer.EnsureInitialized(ref s_transactionStateActive, ref s_classSyncObject, () => new TransactionStateActive());
@@ -176,7 +176,7 @@ namespace System.Transactions
         // Every state must override EnterState
         internal abstract void EnterState(InternalTransaction tx);
 
-        internal virtual void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal virtual void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
@@ -188,7 +188,7 @@ namespace System.Transactions
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
 
-        internal virtual void Rollback(InternalTransaction tx, Exception e)
+        internal virtual void Rollback(InternalTransaction tx, Exception? e)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
@@ -256,7 +256,7 @@ namespace System.Transactions
         // Every state derived from the base must override status
         internal abstract TransactionStatus get_Status(InternalTransaction tx);
 
-        internal virtual void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal virtual void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
@@ -295,7 +295,7 @@ namespace System.Transactions
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
 
-        internal virtual void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal virtual void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             Debug.Fail($"Invalid Event for State; Current State: {GetType()}");
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
@@ -524,9 +524,9 @@ namespace System.Transactions
             return TransactionStatus.Active;
         }
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
-            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler)
+            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?)
                 System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate);
         }
     }
@@ -550,7 +550,7 @@ namespace System.Transactions
             tx._promoteState.EnterState(tx);
             // Note that just because we did an EnterState above does not mean that the state will be
             // the same when the next method is called.
-            return tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
+            return tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
         }
 
         internal override Enlistment EnlistDurable(
@@ -566,7 +566,7 @@ namespace System.Transactions
             {
                 // These circumstances cause promotion
                 tx._promoteState.EnterState(tx);
-                return tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
+                return tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
             }
 
             // Create a durable enlistment
@@ -604,7 +604,7 @@ namespace System.Transactions
             tx._promoteState.EnterState(tx);
 
             // Forward this call
-            tx.State.GetObjectData(tx, serializationInfo, context);
+            tx.State!.GetObjectData(tx, serializationInfo, context);
         }
 
         internal override void CompleteBlockingClone(InternalTransaction tx)
@@ -623,7 +623,7 @@ namespace System.Transactions
             if (tx._phase0Volatiles._preparedVolatileEnlistments ==
                 tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones)
             {
-                tx.State.Phase0VolatilePrepareDone(tx);
+                tx.State!.Phase0VolatilePrepareDone(tx);
             }
         }
 
@@ -652,7 +652,7 @@ namespace System.Transactions
         internal override void Promote(InternalTransaction tx)
         {
             tx._promoteState.EnterState(tx);
-            tx.State.CheckForFinishedTransaction(tx);
+            tx.State!.CheckForFinishedTransaction(tx);
         }
 
         internal override byte[] PromotedToken(InternalTransaction tx)
@@ -660,9 +660,9 @@ namespace System.Transactions
             if (tx.promotedToken == null)
             {
                 tx._promoteState.EnterState(tx);
-                tx.State.CheckForFinishedTransaction(tx);
+                tx.State!.CheckForFinishedTransaction(tx);
             }
-
+            Debug.Assert(tx.promotedToken != null);
             return tx.promotedToken;
         }
     }
@@ -682,7 +682,7 @@ namespace System.Transactions
             // Yeah it's active.
         }
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Store the given values
             tx._asyncCommit = asyncCommit;
@@ -693,7 +693,7 @@ namespace System.Transactions
             TransactionStatePhase0.EnterState(tx);
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Start the process for abort.  From the active state we can transition directly
             // to the aborted state.
@@ -820,7 +820,7 @@ namespace System.Transactions
 
         internal override void DisposeRoot(InternalTransaction tx)
         {
-            tx.State.Rollback(tx, null);
+            tx.State!.Rollback(tx, null);
         }
     }
 
@@ -839,7 +839,7 @@ namespace System.Transactions
             Debug.Assert(tx._promoter != null, "Transaction Promoter is Null entering SubordinateActive");
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Start the process for abort.  From the active state we can transition directly
             // to the aborted state.
@@ -849,6 +849,7 @@ namespace System.Transactions
                 tx._innerException = e;
             }
 
+            Debug.Assert(tx._promoter != null);
             ((ISimpleTransactionSuperior)tx._promoter).Rollback();
             TransactionStateAborted.EnterState(tx);
         }
@@ -861,7 +862,7 @@ namespace System.Transactions
             )
         {
             tx._promoteState.EnterState(tx);
-            return tx.State.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction);
+            return tx.State!.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction);
         }
 
         internal override Enlistment EnlistVolatile(
@@ -872,20 +873,20 @@ namespace System.Transactions
             )
         {
             tx._promoteState.EnterState(tx);
-            return tx.State.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction);
+            return tx.State!.EnlistVolatile(tx, enlistmentNotification, enlistmentOptions, atomicTransaction);
         }
 
         // Every state derived from the base must override status
         internal override TransactionStatus get_Status(InternalTransaction tx)
         {
             tx._promoteState.EnterState(tx);
-            return tx.State.get_Status(tx);
+            return tx.State!.get_Status(tx);
         }
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             tx._promoteState.EnterState(tx);
-            tx.State.AddOutcomeRegistrant(tx, transactionCompletedDelegate);
+            tx.State!.AddOutcomeRegistrant(tx, transactionCompletedDelegate);
         }
 
         internal override bool EnlistPromotableSinglePhase(
@@ -901,14 +902,14 @@ namespace System.Transactions
         internal override void CreateBlockingClone(InternalTransaction tx)
         {
             tx._promoteState.EnterState(tx);
-            tx.State.CreateBlockingClone(tx);
+            tx.State!.CreateBlockingClone(tx);
         }
 
 
         internal override void CreateAbortingClone(InternalTransaction tx)
         {
             tx._promoteState.EnterState(tx);
-            tx.State.CreateAbortingClone(tx);
+            tx.State!.CreateAbortingClone(tx);
         }
     }
 
@@ -937,8 +938,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase0Prepares())
+                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase0Prepares())
                     {
                         break;
                     }
@@ -965,7 +966,7 @@ namespace System.Transactions
                 enlistmentOptions, atomicTransaction);
 
             // Calling durable enlist in Phase0 may cause the transaction to promote.  Leverage the promoted
-            tx.State.RestartCommitIfNeeded(tx);
+            tx.State!.RestartCommitIfNeeded(tx);
             return en;
         }
 
@@ -983,7 +984,7 @@ namespace System.Transactions
                 enlistmentOptions, atomicTransaction);
 
             // Calling durable enlist in Phase0 may cause the transaction to promote.  Leverage the promoted
-            tx.State.RestartCommitIfNeeded(tx);
+            tx.State!.RestartCommitIfNeeded(tx);
             return en;
         }
 
@@ -1040,7 +1041,7 @@ namespace System.Transactions
             return enlistment;
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             ChangeStateTransactionAborted(tx, e);
         }
@@ -1117,8 +1118,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase0Prepares())
+                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase0Prepares())
                     {
                         break;
                     }
@@ -1149,11 +1150,11 @@ namespace System.Transactions
         internal override void Promote(InternalTransaction tx)
         {
             tx._promoteState.EnterState(tx);
-            tx.State.CheckForFinishedTransaction(tx);
+            tx.State!.CheckForFinishedTransaction(tx);
             tx.State.RestartCommitIfNeeded(tx);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -1172,7 +1173,7 @@ namespace System.Transactions
             tx._promoteState.EnterState(tx);
 
             // Forward this call
-            tx.State.GetObjectData(tx, serializationInfo, context);
+            tx.State!.GetObjectData(tx, serializationInfo, context);
 
             // Restart the commit process.
             tx.State.RestartCommitIfNeeded(tx);
@@ -1189,6 +1190,7 @@ namespace System.Transactions
             // Set the transaction state
             CommonEnterState(tx);
 
+            Debug.Assert(tx._committableTransaction != null);
             // Mark the committable transaction as complete.
             tx._committableTransaction._complete = true;
 
@@ -1210,8 +1212,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
                 {
-                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase1Prepares())
+                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase1Prepares())
                     {
                         break;
                     }
@@ -1224,12 +1226,12 @@ namespace System.Transactions
             }
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             ChangeStateTransactionAborted(tx, e);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -1277,7 +1279,7 @@ namespace System.Transactions
             Debug.Assert(tx._phase1Volatiles._volatileEnlistmentCount == 1,
                 "There must be exactly 1 phase 1 volatile enlistment for TransactionStateVolatileSPC");
 
-            tx._phase1Volatiles._volatileEnlistments[0]._twoPhaseState.ChangeStateSinglePhaseCommit(
+            tx._phase1Volatiles._volatileEnlistments[0]._twoPhaseState!.ChangeStateSinglePhaseCommit(
                 tx._phase1Volatiles._volatileEnlistments[0]);
         }
 
@@ -1293,7 +1295,7 @@ namespace System.Transactions
             TransactionStateInDoubt.EnterState(tx);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -1340,7 +1342,7 @@ namespace System.Transactions
             TransactionStateInDoubt.EnterState(tx);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -1366,7 +1368,7 @@ namespace System.Transactions
             }
         }
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             if (transactionCompletedDelegate != null)
             {
@@ -1401,12 +1403,12 @@ namespace System.Transactions
             // Notify the enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the durable enlistment
@@ -1440,12 +1442,12 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Abort is itempotent.  Ignore this if the transaction is already aborted.
         }
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // End Commit Must throw a TransactionAbortedException to let the caller know that the tx aborted.
             throw CreateTransactionAbortedException(tx);
@@ -1478,7 +1480,7 @@ namespace System.Transactions
             // Since the transaction is aborted ignore it.
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             // Yes, yes, yes... I already know.
         }
@@ -1537,13 +1539,13 @@ namespace System.Transactions
             // Notify the phase 0 enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the phase 1 enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Remove this from the timeout list
@@ -1572,7 +1574,7 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
@@ -1600,13 +1602,13 @@ namespace System.Transactions
             // Notify the phase 0 enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the phase 1 enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Remove this from the timeout list
@@ -1635,7 +1637,7 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
@@ -1818,7 +1820,7 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             Debug.Assert(tx.PromotedTransaction != null, "Promoted state not valid for transaction.");
             // Forward this on to the promoted transaction.
@@ -1841,7 +1843,7 @@ namespace System.Transactions
         }
 
 
-        internal override Guid get_Identifier(InternalTransaction tx)
+        internal override Guid get_Identifier(InternalTransaction? tx)
         {
             if (tx != null && tx.PromotedTransaction != null)
             {
@@ -1854,15 +1856,15 @@ namespace System.Transactions
         }
 
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             // Add this guy to the list of people to be notified of the outcome.
-            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler)
+            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?)
                 System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate);
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Store the given values
             tx._asyncCommit = asyncCommit;
@@ -1907,7 +1909,7 @@ namespace System.Transactions
                 if (tx._phase0Volatiles._preparedVolatileEnlistments ==
                     tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones)
                 {
-                    tx.State.Phase0VolatilePrepareDone(tx);
+                    tx.State!.Phase0VolatilePrepareDone(tx);
                 }
             }
             else
@@ -1917,7 +1919,7 @@ namespace System.Transactions
                 Debug.Assert(tx._phase0WaveDependentCloneCount >= 0);
                 if (tx._phase0WaveDependentCloneCount == 0)
                 {
-                    DistributedDependentTransaction dtx = tx._phase0WaveDependentClone;
+                    DistributedDependentTransaction dtx = tx._phase0WaveDependentClone!;
                     tx._phase0WaveDependentClone = null;
 
                     Monitor.Exit(tx);
@@ -1961,7 +1963,7 @@ namespace System.Transactions
                 {
                     // We need to complete our dependent clone on the promoted transaction and null it out
                     // so if we get a new one, a new one will be created on the promoted transaction.
-                    DistributedDependentTransaction dtx = tx._abortingDependentClone;
+                    DistributedDependentTransaction dtx = tx._abortingDependentClone!;
                     tx._abortingDependentClone = null;
 
                     Monitor.Exit(tx);
@@ -1992,6 +1994,7 @@ namespace System.Transactions
             // will handle phase 0 waves.
             if (tx._phase0WaveDependentClone == null)
             {
+                Debug.Assert(tx.PromotedTransaction != null);
                 tx._phase0WaveDependentClone = tx.PromotedTransaction.DependentClone(true);
             }
 
@@ -2013,6 +2016,7 @@ namespace System.Transactions
             {
                 if (null == tx._abortingDependentClone)
                 {
+                    Debug.Assert(tx.PromotedTransaction != null);
                     tx._abortingDependentClone = tx.PromotedTransaction.DependentClone(false);
                 }
                 tx._abortingDependentCloneCount++;
@@ -2044,7 +2048,7 @@ namespace System.Transactions
             // Before forwarding this call to the promoted tx make sure to change
             // the full type info so that only if the promoted tx does not set this
             // then it should be set correctly.
-            serializationInfo.FullTypeName = tx.PromotedTransaction.GetType().FullName;
+            serializationInfo.FullTypeName = tx.PromotedTransaction.GetType().FullName!;
 
             // Now forward the call.
             serializableTx.GetObjectData(serializationInfo, context);
@@ -2088,8 +2092,8 @@ namespace System.Transactions
                 if (tx._innerException == null)
                 {
                     tx._innerException = new TimeoutException(SR.TraceTransactionTimeout);
-                    ;
                 }
+                Debug.Assert(tx.PromotedTransaction != null);
                 tx.PromotedTransaction.Rollback();
 
                 TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
@@ -2155,6 +2159,7 @@ namespace System.Transactions
             // Set the transaction state
             CommonEnterState(tx);
 
+            Debug.Assert(tx.PromotedTransaction != null && tx.PromotedTransaction.RealTransaction != null);
             // Let the distributed transaction know that we want to know about the outcome.
             tx.PromotedTransaction.RealTransaction.InternalTransaction = tx;
         }
@@ -2182,7 +2187,7 @@ namespace System.Transactions
             CommonEnterState(tx);
 
             // Create a transaction with the distributed transaction manager
-            DistributedCommittableTransaction distributedTx = null;
+            DistributedCommittableTransaction? distributedTx = null;
             try
             {
                 TimeSpan newTimeout;
@@ -2235,7 +2240,7 @@ namespace System.Transactions
                 {
                     // There was an exception trying to create the distributed transaction abort
                     // the local transaction and exit.
-                    tx.State.ChangeStateAbortedDuringPromotion(tx);
+                    tx.State!.ChangeStateAbortedDuringPromotion(tx);
                 }
             }
 
@@ -2278,6 +2283,7 @@ namespace System.Transactions
                     volatiles.VolatileDemux = new Phase1VolatileDemultiplexer(tx);
                 }
 
+                Debug.Assert(tx.PromotedTransaction != null);
                 volatiles.VolatileDemux._promotedEnlistment = tx.PromotedTransaction.EnlistVolatile(volatiles.VolatileDemux,
                     phase0 ? EnlistmentOptions.EnlistDuringPrepareRequired : EnlistmentOptions.None);
             }
@@ -2293,6 +2299,7 @@ namespace System.Transactions
             {
                 // Directly enlist the durable enlistment with the resource manager.
                 InternalEnlistment enlistment = tx._durableEnlistment;
+                Debug.Assert(tx.PromotedTransaction != null);
                 IPromotedEnlistment promotedEnlistment = tx.PromotedTransaction.EnlistDurable(
                     enlistment.ResourceManagerIdentifier,
                     (DurableInternalEnlistment)enlistment,
@@ -2317,9 +2324,11 @@ namespace System.Transactions
 
             bool enlistmentsPromoted = false;
 
+            Debug.Assert(tx.PromotedTransaction != null && tx.PromotedTransaction.RealTransaction != null);
             // Tell the real transaction that we want a callback for the outcome.
             tx.PromotedTransaction.RealTransaction.InternalTransaction = tx;
 
+            Debug.Assert(tx.State != null);
             // Promote Phase 0 Volatiles
             try
             {
@@ -2411,7 +2420,7 @@ namespace System.Transactions
 
         internal override void DisposeRoot(InternalTransaction tx)
         {
-            tx.State.Rollback(tx, null);
+            tx.State!.Rollback(tx, null);
         }
     }
 
@@ -2429,7 +2438,7 @@ namespace System.Transactions
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Don't allow this again.
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
@@ -2467,7 +2476,7 @@ namespace System.Transactions
         }
 
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -2491,12 +2500,12 @@ namespace System.Transactions
             CommonEnterState(tx);
 
             // Use the asynchronous commit provided by the promoted transaction
-            var ctx = (DistributedCommittableTransaction)tx.PromotedTransaction;
+            var ctx = (DistributedCommittableTransaction)tx.PromotedTransaction!;
             ctx.BeginCommit(tx);
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Don't allow this again.
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
@@ -2543,10 +2552,10 @@ namespace System.Transactions
                 // Broadcast preprepare to the volatile subordinates
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(
+                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(
                         tx._phase0Volatiles._volatileEnlistments[i]);
 
-                    if (!tx.State.ContinuePhase0Prepares())
+                    if (!tx.State!.ContinuePhase0Prepares())
                     {
                         break;
                     }
@@ -2566,6 +2575,7 @@ namespace System.Transactions
             Monitor.Exit(tx);
             try
             {
+                Debug.Assert(tx._phase0Volatiles.VolatileDemux._promotedEnlistment != null);
                 // Tell the distributed TM that the volatile enlistments are prepared
                 tx._phase0Volatiles.VolatileDemux._promotedEnlistment.Prepared();
             }
@@ -2582,7 +2592,7 @@ namespace System.Transactions
         }
 
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -2616,7 +2626,7 @@ namespace System.Transactions
             // If at this point there are phase1 dependent clones abort the transaction
             if (tx._phase1Volatiles._dependentClones != 0)
             {
-                tx.State.ChangeStateTransactionAborted(tx, null);
+                tx.State!.ChangeStateTransactionAborted(tx, null);
                 return;
             }
 
@@ -2632,9 +2642,9 @@ namespace System.Transactions
                 // Broadcast preprepare to the volatile subordinates
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(
+                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(
                         tx._phase1Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase1Prepares())
+                    if (!tx.State!.ContinuePhase1Prepares())
                     {
                         break;
                     }
@@ -2659,7 +2669,7 @@ namespace System.Transactions
         }
 
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -2679,6 +2689,7 @@ namespace System.Transactions
             Monitor.Exit(tx);
             try
             {
+                Debug.Assert(tx._phase1Volatiles.VolatileDemux._promotedEnlistment != null);
                 // Tell the distributed TM that the volatile enlistments are prepared
                 tx._phase1Volatiles.VolatileDemux._promotedEnlistment.Prepared();
             }
@@ -2739,7 +2750,7 @@ namespace System.Transactions
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Don't allow this again.
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
@@ -2764,7 +2775,7 @@ namespace System.Transactions
         }
 
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             // Don't do this yet wait until all of the notifications come back.
         }
@@ -2795,6 +2806,7 @@ namespace System.Transactions
                 Monitor.Exit(tx);
                 try
                 {
+                    Debug.Assert(tx._phase0Volatiles.VolatileDemux._promotedEnlistment != null);
                     // Tell the distributed TM that the tx aborted.
                     tx._phase0Volatiles.VolatileDemux._promotedEnlistment.ForceRollback();
                 }
@@ -2805,6 +2817,7 @@ namespace System.Transactions
             }
             else
             {
+                Debug.Assert(tx.PromotedTransaction != null);
                 // Otherwise make sure that the transaction rolls back.
                 tx.PromotedTransaction.Rollback();
             }
@@ -2835,6 +2848,7 @@ namespace System.Transactions
             Monitor.Exit(tx);
             try
             {
+                Debug.Assert(tx._phase1Volatiles.VolatileDemux._promotedEnlistment != null);
                 // Tell the distributed TM that the tx aborted.
                 tx._phase1Volatiles.VolatileDemux._promotedEnlistment.ForceRollback();
             }
@@ -2876,7 +2890,7 @@ namespace System.Transactions
         }
 
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             if (transactionCompletedDelegate != null)
             {
@@ -2920,6 +2934,7 @@ namespace System.Transactions
 
         internal override Guid get_Identifier(InternalTransaction tx)
         {
+            Debug.Assert(tx.PromotedTransaction != null);
             return tx.PromotedTransaction.Identifier;
         }
 
@@ -2930,8 +2945,8 @@ namespace System.Transactions
 
         protected abstract void PromotedTransactionOutcome(InternalTransaction tx);
 
-        private static WaitCallback s_signalMethod;
-        private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback));
+        private static WaitCallback? s_signalMethod;
+        private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback!));
 
 
         private static void SignalCallback(object state)
@@ -2985,13 +3000,13 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Already done.
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionAbortedException.Create(SR.TransactionAborted, tx._innerException, tx.DistributedTxId);
         }
@@ -3043,7 +3058,7 @@ namespace System.Transactions
         }
 
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             // This may come from a promotable single phase enlistments abort response.
         }
@@ -3289,7 +3304,7 @@ namespace System.Transactions
             CommonEnterState(tx);
 
             // Create a transaction with the distributed transaction manager
-            DistributedTransaction distributedTx = null;
+            DistributedTransaction? distributedTx = null;
             try
             {
                 // Ask the delegation interface to promote the transaction.
@@ -3316,15 +3331,15 @@ namespace System.Transactions
             }
             finally
             {
-                if (((object)distributedTx) == null)
+                if (((object?)distributedTx) == null)
                 {
                     // There was an exception trying to create the distributed transaction abort
                     // the local transaction and exit.
-                    tx.State.ChangeStateAbortedDuringPromotion(tx);
+                    tx.State!.ChangeStateAbortedDuringPromotion(tx);
                 }
             }
 
-            if (((object)distributedTx) == null)
+            if (((object?)distributedTx) == null)
             {
                 return;
             }
@@ -3375,7 +3390,7 @@ namespace System.Transactions
     // except for the way that commit happens.
     internal class TransactionStateDelegated : TransactionStateDelegatedBase
     {
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Store the given values
             tx._asyncCommit = asyncCommit;
@@ -3389,6 +3404,7 @@ namespace System.Transactions
 
         internal override bool PromoteDurable(InternalTransaction tx)
         {
+            Debug.Assert(tx._durableEnlistment != null);
             // Let the enlistment know that it has been delegated.  For this type of enlistment that
             // is really all that needs to be done.
             tx._durableEnlistment.State.ChangeStateDelegated(tx._durableEnlistment);
@@ -3403,7 +3419,7 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Pass the Rollback through the promotable single phase enlistment to be
             // certain it is notified.
@@ -3516,7 +3532,7 @@ namespace System.Transactions
             return false;
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Start the process for abort.  Transitioning to the Aborted state will cause
             // the tx.durableEnlistment to get aborted, which is how the non-MSDTC
@@ -3538,16 +3554,16 @@ namespace System.Transactions
         }
 
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             // Add this guy to the list of people to be notified of the outcome.
-            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler)
+            tx._transactionCompletedDelegate = (TransactionCompletedEventHandler?)
                 System.Delegate.Combine(tx._transactionCompletedDelegate, transactionCompletedDelegate);
         }
 
 
         // Start the commit processing by transitioning to TransactionStatePromotedNonMSDTCPhase0.
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             tx._asyncCommit = asyncCommit;
             tx._asyncCallback = asyncCallback;
@@ -3572,7 +3588,7 @@ namespace System.Transactions
                 if (tx._phase0Volatiles._preparedVolatileEnlistments ==
                     tx._phase0VolatileWaveCount + tx._phase0Volatiles._dependentClones)
                 {
-                    tx.State.Phase0VolatilePrepareDone(tx);
+                    tx.State!.Phase0VolatilePrepareDone(tx);
                 }
             }
         }
@@ -3610,7 +3626,7 @@ namespace System.Transactions
                 tx._innerException);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             // Just transition to Aborted. The PSPE will be told to rollback thru the durableEnlistment.
             // This is also overridden in TransactionStatePromotedNonMSDTCSinglePhaseCommit
@@ -3672,7 +3688,7 @@ namespace System.Transactions
 
         internal override void DisposeRoot(InternalTransaction tx)
         {
-            tx.State.Rollback(tx, null);
+            tx.State!.Rollback(tx, null);
         }
     }
 
@@ -3700,8 +3716,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase0Prepares())
+                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase0Prepares())
                     {
                         break;
                     }
@@ -3714,12 +3730,12 @@ namespace System.Transactions
             }
         }
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             ChangeStateTransactionAborted(tx, e);
         }
@@ -3744,8 +3760,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < volatileCount; i++)
                 {
-                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase0Prepares())
+                    tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase0Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase0Prepares())
                     {
                         break;
                     }
@@ -3779,6 +3795,7 @@ namespace System.Transactions
             // Set the transaction state
             CommonEnterState(tx);
 
+            Debug.Assert(tx._committableTransaction != null);
             // Mark the committable transaction as complete.
             tx._committableTransaction._complete = true;
 
@@ -3794,8 +3811,8 @@ namespace System.Transactions
                 // Broadcast prepare to the phase 0 enlistments
                 for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
                 {
-                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]);
-                    if (!tx.State.ContinuePhase1Prepares())
+                    tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.ChangeStatePreparing(tx._phase1Volatiles._volatileEnlistments[i]);
+                    if (!tx.State!.ContinuePhase1Prepares())
                     {
                         break;
                     }
@@ -3809,12 +3826,12 @@ namespace System.Transactions
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             ChangeStateTransactionAborted(tx, e);
         }
@@ -3879,6 +3896,7 @@ namespace System.Transactions
         {
             CommonEnterState(tx);
 
+            Debug.Assert(tx._durableEnlistment != null);
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
             {
@@ -3892,12 +3910,12 @@ namespace System.Transactions
             tx._durableEnlistment.State.ChangeStateCommitting(tx._durableEnlistment);
         }
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // We have told the PSPE enlistment to do a single phase commit. It's too late to rollback.
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
@@ -3915,7 +3933,7 @@ namespace System.Transactions
             TransactionStatePromotedNonMSDTCIndoubt.EnterState(tx);
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             if (tx._innerException == null)
             {
@@ -3994,7 +4012,7 @@ namespace System.Transactions
             }
         }
 
-        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler transactionCompletedDelegate)
+        internal override void AddOutcomeRegistrant(InternalTransaction tx, TransactionCompletedEventHandler? transactionCompletedDelegate)
         {
             if (transactionCompletedDelegate != null)
             {
@@ -4043,8 +4061,8 @@ namespace System.Transactions
 
         protected abstract void PromotedTransactionOutcome(InternalTransaction tx);
 
-        private static WaitCallback s_signalMethod;
-        private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback));
+        private static WaitCallback? s_signalMethod;
+        private static WaitCallback SignalMethod => LazyInitializer.EnsureInitialized(ref s_signalMethod, ref s_classSyncObject, () => new WaitCallback(SignalCallback!));
 
         private static void SignalCallback(object state)
         {
@@ -4069,12 +4087,12 @@ namespace System.Transactions
             // Notify the enlistments that the transaction has aborted
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the durable enlistment
@@ -4099,12 +4117,12 @@ namespace System.Transactions
             return TransactionStatus.Aborted;
         }
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Already done.
         }
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             throw TransactionAbortedException.Create(SR.TransactionAborted, tx._innerException, tx.DistributedTxId);
         }
@@ -4129,7 +4147,7 @@ namespace System.Transactions
             // Since the transaction is aborted ignore it.
         }
 
-        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception e)
+        internal override void ChangeStateTransactionAborted(InternalTransaction tx, Exception? e)
         {
             // This may come from a promotable single phase enlistments abort response.
         }
@@ -4167,13 +4185,13 @@ namespace System.Transactions
             // Notify the phase 0 enlistments that the transaction has committed
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the phase 1 enlistments that the transaction has committed
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Fire Completion for anyone listening
@@ -4211,13 +4229,13 @@ namespace System.Transactions
             // Notify the phase 0 enlistments that the transaction is indoubt
             for (int i = 0; i < tx._phase0Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]);
+                tx._phase0Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase0Volatiles._volatileEnlistments[i]);
             }
 
             // Notify the phase 1 enlistments that the transaction is indoubt
             for (int i = 0; i < tx._phase1Volatiles._volatileEnlistmentCount; i++)
             {
-                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]);
+                tx._phase1Volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(tx._phase1Volatiles._volatileEnlistments[i]);
             }
 
             // Fire Completion for anyone listening
@@ -4287,7 +4305,7 @@ namespace System.Transactions
             CommonEnterState(tx);
 
             // We are never going to have an DistributedTransaction for this one.
-            DistributedTransaction distributedTx = null;
+            DistributedTransaction? distributedTx = null;
             try
             {
                 // Ask the delegation interface to promote the transaction.
@@ -4319,7 +4337,7 @@ namespace System.Transactions
                 if (tx.promotedToken == null)
                 {
                     // There was an exception trying to promote the transaction.
-                    tx.State.ChangeStateAbortedDuringPromotion(tx);
+                    tx.State!.ChangeStateAbortedDuringPromotion(tx);
                 }
             }
         }
@@ -4337,7 +4355,7 @@ namespace System.Transactions
         }
 
 
-        internal override void Rollback(InternalTransaction tx, Exception e)
+        internal override void Rollback(InternalTransaction tx, Exception? e)
         {
             // Pass the Rollback through the promotable single phase enlistment to be
             // certain it is notified.
@@ -4347,6 +4365,7 @@ namespace System.Transactions
                 tx._innerException = e;
             }
 
+            Debug.Assert(tx.PromotedTransaction != null);
             tx.PromotedTransaction.Rollback();
             TransactionStatePromotedAborted.EnterState(tx);
         }
@@ -4435,18 +4454,18 @@ namespace System.Transactions
             }
         }
 
-        internal DistributedTransaction PSPEPromote(InternalTransaction tx)
+        internal DistributedTransaction? PSPEPromote(InternalTransaction tx)
         {
             bool changeToReturnState = true;
 
-            TransactionState returnState = tx.State;
+            TransactionState? returnState = tx.State;
             Debug.Assert(returnState == TransactionStateDelegated ||
                 returnState == TransactionStateDelegatedSubordinate ||
                 returnState == TransactionStateDelegatedNonMSDTC,
                 "PSPEPromote called from state other than TransactionStateDelegated[NonMSDTC]");
             CommonEnterState(tx);
 
-            DistributedTransaction distributedTx = null;
+            DistributedTransaction? distributedTx = null;
             try
             {
                 if (tx._attemptingPSPEPromote)
@@ -4461,7 +4480,8 @@ namespace System.Transactions
                 }
                 tx._attemptingPSPEPromote = true;
 
-                byte[] propagationToken = tx._promoter.Promote();
+                Debug.Assert(tx._promoter != null);
+                byte[]? propagationToken = tx._promoter.Promote();
 
                 // If the PromoterType is NOT MSDTC, then we can't assume that the returned
                 // byte[] is an MSDTC propagation token and we can't create an DistributedTransaction from it.
@@ -4513,7 +4533,7 @@ namespace System.Transactions
                     try
                     {
                         distributedTx = TransactionInterop.GetDistributedTransactionFromTransmitterPropagationToken(
-                                            propagationToken
+                                            propagationToken!
                                             );
                     }
                     catch (ArgumentException e)
@@ -4595,7 +4615,7 @@ namespace System.Transactions
 
             // Now we need to create the durable enlistment that will replace the PSPE enlistment. Use the internalEnlistment of
             // this newly created durable enlistment as the tx.durableEnlistment.
-            enlistment = tx.State.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
+            enlistment = tx.State!.EnlistDurable(tx, resourceManagerIdentifier, enlistmentNotification, enlistmentOptions, atomicTransaction);
             tx._durableEnlistment = enlistment.InternalEnlistment;
 
             return enlistment;
@@ -4655,6 +4675,7 @@ namespace System.Transactions
             // Forward this on to the promotable single phase enlisment
             Monitor.Exit(tx);
 
+            Debug.Assert(tx._durableEnlistment != null);
             TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
             if (etwLog.IsEnabled())
             {
@@ -4691,6 +4712,7 @@ namespace System.Transactions
             Monitor.Exit(tx);
             try
             {
+                Debug.Assert(tx._durableEnlistment != null);
                 TransactionsEtwProvider etwLog = TransactionsEtwProvider.Log;
                 if (etwLog.IsEnabled())
                 {
@@ -4707,7 +4729,7 @@ namespace System.Transactions
         }
 
 
-        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback asyncCallback, object asyncState)
+        internal override void BeginCommit(InternalTransaction tx, bool asyncCommit, AsyncCallback? asyncCallback, object? asyncState)
         {
             // Initiate the commit process.
             throw TransactionException.CreateTransactionStateException(tx._innerException, tx.DistributedTxId);
index d712b88..d79a269 100644 (file)
@@ -9,13 +9,13 @@ namespace System.Transactions
 {
     internal class CheapUnfairReaderWriterLock
     {
-        private object _writerFinishedEvent;
+        private object? _writerFinishedEvent;
 
         private int _readersIn;
         private int _readersOut;
         private bool _writerPresent;
 
-        private object _syncRoot;
+        private object? _syncRoot;
 
         // Spin lock params
         private const int MAX_SPIN_COUNT = 100;
@@ -283,14 +283,14 @@ namespace System.Transactions
 
             while (currentBucketSet.AbsoluteTimeout != txNew.AbsoluteTimeout)
             {
-                BucketSet lastBucketSet = null;
+                BucketSet? lastBucketSet = null;
                 do
                 {
-                    WeakReference nextSetWeak = (WeakReference)currentBucketSet.nextSetWeak;
-                    BucketSet nextBucketSet = null;
+                    WeakReference? nextSetWeak = (WeakReference?)currentBucketSet.nextSetWeak;
+                    BucketSet? nextBucketSet = null;
                     if (nextSetWeak != null)
                     {
-                        nextBucketSet = (BucketSet)nextSetWeak.Target;
+                        nextBucketSet = (BucketSet?)nextSetWeak.Target;
                     }
 
                     if (nextBucketSet == null)
@@ -303,7 +303,7 @@ namespace System.Transactions
                         BucketSet newBucketSet = new BucketSet(this, txNew.AbsoluteTimeout);
                         WeakReference newSetWeak = new WeakReference(newBucketSet);
 
-                        WeakReference oldNextSetWeak = (WeakReference)Interlocked.CompareExchange(
+                        WeakReference? oldNextSetWeak = (WeakReference?)Interlocked.CompareExchange(
                             ref currentBucketSet.nextSetWeak, newSetWeak, nextSetWeak);
                         if (oldNextSetWeak == nextSetWeak)
                         {
@@ -330,15 +330,16 @@ namespace System.Transactions
                     BucketSet newBucketSet = new BucketSet(this, txNew.AbsoluteTimeout);
                     WeakReference newSetWeak = new WeakReference(newBucketSet);
 
+                    Debug.Assert(lastBucketSet != null);
                     newBucketSet.nextSetWeak = lastBucketSet.nextSetWeak;
-                    WeakReference oldNextSetWeak = (WeakReference)Interlocked.CompareExchange(
+                    WeakReference? oldNextSetWeak = (WeakReference?)Interlocked.CompareExchange(
                         ref lastBucketSet.nextSetWeak, newSetWeak, newBucketSet.nextSetWeak);
                     if (oldNextSetWeak == newBucketSet.nextSetWeak)
                     {
                         // Ladies and Gentlemen we have a winner.
                         if (oldNextSetWeak != null)
                         {
-                            BucketSet oldSet = (BucketSet)oldNextSetWeak.Target;
+                            BucketSet? oldSet = (BucketSet?)oldNextSetWeak.Target;
                             if (oldSet != null)
                             {
                                 // prev references are just there to root things for the GC.  If this object is
@@ -375,13 +376,14 @@ namespace System.Transactions
         // Remove a transaction from the table.
         internal void Remove(InternalTransaction tx)
         {
+            Debug.Assert(tx._tableBucket != null);
             tx._tableBucket.Remove(tx);
             tx._tableBucket = null;
         }
 
 
         // Process a timer event
-        private void ThreadTimer(object state)
+        private void ThreadTimer(object? state)
         {
             //
             // Theory of operation.
@@ -409,20 +411,20 @@ namespace System.Transactions
             // that point will timeout so once we've found it then it is just a matter of traversing the
             // structure.
             //
-            BucketSet lastBucketSet = null;
+            BucketSet? lastBucketSet = null;
             BucketSet currentBucketSet = _headBucketSet; // The list always has a head.
 
             // Acquire a writer lock before checking to see if we should disable the timer.
             // Adding of transactions acquires a reader lock and might insert a new BucketSet.
             // If that races with our check for a BucketSet existing, we may not timeout that
             // transaction that is being added.
-            WeakReference nextWeakSet = null;
-            BucketSet nextBucketSet = null;
+            WeakReference? nextWeakSet = null;
+            BucketSet? nextBucketSet = null;
 
-            nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
+            nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak;
             if (nextWeakSet != null)
             {
-                nextBucketSet = (BucketSet)nextWeakSet.Target;
+                nextBucketSet = (BucketSet?)nextWeakSet.Target;
             }
 
             if (nextBucketSet == null)
@@ -431,10 +433,10 @@ namespace System.Transactions
                 try
                 {
                     // Access the nextBucketSet again in writer lock to account for any race before disabling the timeout.
-                    nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
+                    nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak;
                     if (nextWeakSet != null)
                     {
-                        nextBucketSet = (BucketSet)nextWeakSet.Target;
+                        nextBucketSet = (BucketSet?)nextWeakSet.Target;
                     }
 
                     if (nextBucketSet == null)
@@ -470,14 +472,14 @@ namespace System.Transactions
             {
                 do
                 {
-                    nextWeakSet = (WeakReference)currentBucketSet.nextSetWeak;
+                    nextWeakSet = (WeakReference?)currentBucketSet.nextSetWeak;
                     if (nextWeakSet == null)
                     {
                         // Nothing more to do.
                         return;
                     }
 
-                    nextBucketSet = (BucketSet)nextWeakSet.Target;
+                    nextBucketSet = (BucketSet?)nextWeakSet.Target;
                     if (nextBucketSet == null)
                     {
                         // Again nothing more to do.
@@ -498,19 +500,19 @@ namespace System.Transactions
                 // expires, the thread will walk the list again, find the appropriate BucketSet to pinch off, and
                 // then time out the transactions. This means that it is possible for a transaction to live a bit longer,
                 // but not much.
-                WeakReference abortingSetsWeak =
-                    (WeakReference)Interlocked.CompareExchange(ref lastBucketSet.nextSetWeak, null, nextWeakSet);
+                WeakReference? abortingSetsWeak =
+                    (WeakReference?)Interlocked.CompareExchange(ref lastBucketSet.nextSetWeak, null, nextWeakSet);
 
                 if (abortingSetsWeak == nextWeakSet)
                 {
                     // Yea - now proceed to abort the transactions.
-                    BucketSet abortingBucketSets = null;
+                    BucketSet? abortingBucketSets = null;
 
                     do
                     {
                         if (abortingSetsWeak != null)
                         {
-                            abortingBucketSets = (BucketSet)abortingSetsWeak.Target;
+                            abortingBucketSets = (BucketSet?)abortingSetsWeak.Target;
                         }
                         else
                         {
@@ -519,7 +521,7 @@ namespace System.Transactions
                         if (abortingBucketSets != null)
                         {
                             abortingBucketSets.TimeoutTransactions();
-                            abortingSetsWeak = (WeakReference)abortingBucketSets.nextSetWeak;
+                            abortingSetsWeak = (WeakReference?)abortingBucketSets.nextSetWeak;
                         }
                     }
                     while (abortingBucketSets != null);
@@ -539,8 +541,8 @@ namespace System.Transactions
     internal class BucketSet
     {
         // Buckets are kept in sets.  Each element of a set will have the same absoluteTimeout.
-        internal object nextSetWeak;
-        internal BucketSet prevSet;
+        internal object? nextSetWeak;
+        internal BucketSet? prevSet;
 
         private readonly TransactionTable _table;
 
@@ -573,16 +575,16 @@ namespace System.Transactions
 
         internal void TimeoutTransactions()
         {
-            Bucket currentBucket = headBucket;
+            Bucket? currentBucket = headBucket;
             // It will always have a head.
             do
             {
                 currentBucket.TimeoutTransactions();
 
-                WeakReference nextWeakBucket = (WeakReference)currentBucket.nextBucketWeak;
+                WeakReference? nextWeakBucket = (WeakReference?)currentBucket.nextBucketWeak;
                 if (nextWeakBucket != null)
                 {
-                    currentBucket = (Bucket)nextWeakBucket.Target;
+                    currentBucket = (Bucket?)nextWeakBucket.Target;
                 }
                 else
                 {
@@ -599,9 +601,9 @@ namespace System.Transactions
         private bool _timedOut;
         private int _index;
         private readonly int _size;
-        private readonly InternalTransaction[] _transactions;
-        internal WeakReference nextBucketWeak;
-        private Bucket _previous;
+        private readonly InternalTransaction?[] _transactions;
+        internal WeakReference? nextBucketWeak;
+        private Bucket? _previous;
 
         private readonly BucketSet _owningSet;
 
@@ -630,7 +632,7 @@ namespace System.Transactions
                 {
                     lock (tx)
                     {
-                        tx.State.Timeout(tx);
+                        tx.State!.Timeout(tx);
                     }
                 }
             }
@@ -669,12 +671,12 @@ namespace System.Transactions
             for (i = 0; i <= transactionCount && i < _size; i++)
             {
                 Debug.Assert(transactionCount == _index, "Index changed timing out transactions");
-                InternalTransaction tx = _transactions[i];
+                InternalTransaction? tx = _transactions[i];
                 if (tx != null)
                 {
                     lock (tx)
                     {
-                        tx.State.Timeout(tx);
+                        tx.State!.Timeout(tx);
                     }
                 }
             }
index 0dfd048..164f2b1 100644 (file)
@@ -34,7 +34,7 @@ namespace System.Transactions
 
         public override int GetHashCode() => base.GetHashCode();  // Don't have anything better to do.
 
-        public override bool Equals(object obj) => obj is TransactionTraceIdentifier && Equals((TransactionTraceIdentifier)obj);
+        public override bool Equals(object? obj) => obj is TransactionTraceIdentifier transactionTraceId && Equals(transactionTraceId);
 
         public bool Equals(TransactionTraceIdentifier other) =>
             _cloneIdentifier == other._cloneIdentifier &&
index f751767..c6fd036 100644 (file)
@@ -177,17 +177,17 @@ namespace System.Transactions
         // Transactions Events
         //
         [NonEvent]
-        public static string IdOf(object value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance;
+        public static string IdOf(object? value) => value != null ? value.GetType().Name + "#" + GetHashCode(value) : NullInstance;
 
         [NonEvent]
-        public static int GetHashCode(object value) => value?.GetHashCode() ?? 0;
+        public static int GetHashCode(object? value) => value?.GetHashCode() ?? 0;
 
         #region Transaction Creation
         /// <summary>Trace an event when a new transaction is created.</summary>
         /// <param name="transaction">The transaction that was created.</param>
         /// <param name="type">The type of transaction.</param>Method
         [NonEvent]
-        internal void TransactionCreated(Transaction transaction, string type)
+        internal void TransactionCreated(Transaction transaction, string? type)
         {
             Debug.Assert(transaction != null, "Transaction needed for the ETW event.");
 
@@ -201,7 +201,7 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTION_CREATED_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Informational, Task = Tasks.Transaction, Opcode = Opcodes.Create, Message = "Transaction Created. ID is {0}, type is {1}")]
-        private void TransactionCreated(string transactionIdentifier, string type)
+        private void TransactionCreated(string transactionIdentifier, string? type)
         {
             SetActivityId(transactionIdentifier);
             WriteEvent(TRANSACTION_CREATED_EVENTID, transactionIdentifier, type);
@@ -267,7 +267,7 @@ namespace System.Transactions
         /// <param name="message">The message for the exception.</param>
         /// <param name="innerExceptionStr">The inner exception.</param>
         [NonEvent]
-        internal void TransactionExceptionTrace(TraceSourceType traceSource, TransactionExceptionType type, string message, string innerExceptionStr)
+        internal void TransactionExceptionTrace(TraceSourceType traceSource, TransactionExceptionType type, string? message, string? innerExceptionStr)
         {
             if (IsEnabled(EventLevel.Error, ALL_KEYWORDS))
             {
@@ -287,7 +287,7 @@ namespace System.Transactions
         /// <param name="message">The message for the exception.</param>
         /// <param name="innerExceptionStr">The inner exception.</param>
         [NonEvent]
-        internal void TransactionExceptionTrace(TransactionExceptionType type, string message, string innerExceptionStr)
+        internal void TransactionExceptionTrace(TransactionExceptionType type, string? message, string? innerExceptionStr)
         {
             if (IsEnabled(EventLevel.Error, ALL_KEYWORDS))
             {
@@ -296,14 +296,14 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTION_EXCEPTION_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Error, Task = Tasks.TransactionException, Message = "Transaction Exception. Type is {0}, message is {1}, InnerException is {2}")]
-        private void TransactionExceptionBase(string type, string message, string innerExceptionStr)
+        private void TransactionExceptionBase(string? type, string? message, string? innerExceptionStr)
         {
             SetActivityId(string.Empty);
             WriteEvent(TRANSACTION_EXCEPTION_BASE_EVENTID, type, message, innerExceptionStr);
         }
 
         [Event(TRANSACTION_EXCEPTION_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Error, Task = Tasks.TransactionException, Message = "Transaction Exception. Type is {0}, message is {1}, InnerException is {2}")]
-        private void TransactionExceptionLtm(string type, string message, string innerExceptionStr)
+        private void TransactionExceptionLtm(string? type, string? message, string? innerExceptionStr)
         {
             SetActivityId(string.Empty);
             WriteEvent(TRANSACTION_EXCEPTION_LTM_EVENTID, type, message, innerExceptionStr);
@@ -315,7 +315,7 @@ namespace System.Transactions
         /// <param name="type">The type of transaction.</param>
         /// <param name="operation">The operationont the transaction.</param>
         [NonEvent]
-        internal void InvalidOperation(string type, string operation)
+        internal void InvalidOperation(string? type, string? operation)
         {
             if (IsEnabled(EventLevel.Error, ALL_KEYWORDS))
             {
@@ -324,7 +324,7 @@ namespace System.Transactions
             }
         }
         [Event(TRANSACTION_INVALID_OPERATION_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Error, Task = Tasks.Transaction, Opcode = Opcodes.InvalidOperation, Message = "Transaction Invalid Operation. ID is {0}, type is {1} and operation is {2}")]
-        private void TransactionInvalidOperation(string transactionIdentifier, string type, string operation)
+        private void TransactionInvalidOperation(string? transactionIdentifier, string? type, string? operation)
         {
             SetActivityId(string.Empty);
             WriteEvent(TRANSACTION_INVALID_OPERATION_EVENTID, transactionIdentifier, type, operation);
@@ -336,7 +336,7 @@ namespace System.Transactions
         /// <param name="transaction">The transaction to rollback.</param>
         /// <param name="type">The type of transaction.</param>
         [NonEvent]
-        internal void TransactionRollback(Transaction transaction, string type)
+        internal void TransactionRollback(Transaction transaction, string? type)
         {
             Debug.Assert(transaction != null, "Transaction needed for the ETW event.");
 
@@ -350,7 +350,7 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTION_ROLLBACK_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Warning, Task = Tasks.Transaction, Opcode = Opcodes.Rollback, Message = "Transaction Rollback. ID is {0}, type is {1}")]
-        private void TransactionRollback(string transactionIdentifier, string type)
+        private void TransactionRollback(string transactionIdentifier, string? type)
         {
             SetActivityId(transactionIdentifier);
             WriteEvent(TRANSACTION_ROLLBACK_EVENTID, transactionIdentifier, type);
@@ -362,7 +362,7 @@ namespace System.Transactions
         /// <param name="transaction">The transaction that do dependent clone.</param>
         /// <param name="type">The type of transaction.</param>
         [NonEvent]
-        internal void TransactionDependentCloneComplete(Transaction transaction, string type)
+        internal void TransactionDependentCloneComplete(Transaction transaction, string? type)
         {
             Debug.Assert(transaction != null, "Transaction needed for the ETW event.");
 
@@ -376,7 +376,7 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTION_DEPENDENT_CLONE_COMPLETE_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Informational, Task = Tasks.Transaction, Opcode = Opcodes.DependentCloneComplete, Message = "Transaction Dependent Clone Completed. ID is {0}, type is {1}")]
-        private void TransactionDependentCloneComplete(string transactionIdentifier, string type)
+        private void TransactionDependentCloneComplete(string transactionIdentifier, string? type)
         {
             SetActivityId(transactionIdentifier);
             WriteEvent(TRANSACTION_DEPENDENT_CLONE_COMPLETE_EVENTID, transactionIdentifier, type);
@@ -388,7 +388,7 @@ namespace System.Transactions
         /// <param name="transaction">The transaction to commit.</param>
         /// <param name="type">The type of transaction.</param>
         [NonEvent]
-        internal void TransactionCommit(Transaction transaction, string type)
+        internal void TransactionCommit(Transaction transaction, string? type)
         {
             Debug.Assert(transaction != null, "Transaction needed for the ETW event.");
 
@@ -402,7 +402,7 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTION_COMMIT_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Transaction, Opcode = Opcodes.Commit, Message = "Transaction Commit: ID is {0}, type is {1}")]
-        private void TransactionCommit(string transactionIdentifier, string type)
+        private void TransactionCommit(string transactionIdentifier, string? type)
         {
             SetActivityId(transactionIdentifier);
             WriteEvent(TRANSACTION_COMMIT_EVENTID, transactionIdentifier, type);
@@ -592,7 +592,7 @@ namespace System.Transactions
         /// <param name="thisOrContextObject">'this', or another object that serves to provide context for the operation.</param>
         /// <param name="methodname">The name of method.</param>
         [NonEvent]
-        internal void MethodEnter(TraceSourceType traceSource, object thisOrContextObject, [CallerMemberName] string methodname = null)
+        internal void MethodEnter(TraceSourceType traceSource, object? thisOrContextObject, [CallerMemberName] string? methodname = null)
         {
             if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
             {
@@ -615,7 +615,7 @@ namespace System.Transactions
         /// <param name="traceSource"> trace source</param>
         /// <param name="methodname">The name of method.</param>
         [NonEvent]
-        internal void MethodEnter(TraceSourceType traceSource, [CallerMemberName] string methodname = null)
+        internal void MethodEnter(TraceSourceType traceSource, [CallerMemberName] string? methodname = null)
         {
             if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
             {
@@ -635,19 +635,19 @@ namespace System.Transactions
         }
 
         [Event(METHOD_ENTER_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")]
-        private void MethodEnterTraceLtm(string thisOrContextObject, string methodname)
+        private void MethodEnterTraceLtm(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_ENTER_LTM_EVENTID, thisOrContextObject, methodname);
         }
         [Event(METHOD_ENTER_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")]
-        private void MethodEnterTraceBase(string thisOrContextObject, string methodname)
+        private void MethodEnterTraceBase(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_ENTER_BASE_EVENTID, thisOrContextObject, methodname);
         }
         [Event(METHOD_ENTER_DISTRIBUTED_EVENTID, Keywords = Keywords.TraceDistributed, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Enter, Message = "Enter method : {0}.{1}")]
-        private void MethodEnterTraceDistributed(string thisOrContextObject, string methodname)
+        private void MethodEnterTraceDistributed(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_ENTER_DISTRIBUTED_EVENTID, thisOrContextObject, methodname);
@@ -660,7 +660,7 @@ namespace System.Transactions
         /// <param name="thisOrContextObject">'this', or another object that serves to provide context for the operation.</param>
         /// <param name="methodname">The name of method.</param>
         [NonEvent]
-        internal void MethodExit(TraceSourceType traceSource, object thisOrContextObject, [CallerMemberName] string methodname = null)
+        internal void MethodExit(TraceSourceType traceSource, object? thisOrContextObject, [CallerMemberName] string? methodname = null)
         {
             if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
             {
@@ -683,7 +683,7 @@ namespace System.Transactions
         /// <param name="traceSource"> trace source</param>
         /// <param name="methodname">The name of method.</param>
         [NonEvent]
-        internal void MethodExit(TraceSourceType traceSource, [CallerMemberName] string methodname = null)
+        internal void MethodExit(TraceSourceType traceSource, [CallerMemberName] string? methodname = null)
         {
             if (IsEnabled(EventLevel.Verbose, ALL_KEYWORDS))
             {
@@ -703,19 +703,19 @@ namespace System.Transactions
         }
 
         [Event(METHOD_EXIT_LTM_EVENTID, Keywords = Keywords.TraceLtm, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")]
-        private void MethodExitTraceLtm(string thisOrContextObject, string methodname)
+        private void MethodExitTraceLtm(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_EXIT_LTM_EVENTID, thisOrContextObject, methodname);
         }
         [Event(METHOD_EXIT_BASE_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")]
-        private void MethodExitTraceBase(string thisOrContextObject, string methodname)
+        private void MethodExitTraceBase(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_EXIT_BASE_EVENTID, thisOrContextObject, methodname);
         }
         [Event(METHOD_EXIT_DISTRIBUTED_EVENTID, Keywords = Keywords.TraceDistributed, Level = EventLevel.Verbose, Task = Tasks.Method, Opcode = Opcodes.Exit, Message = "Exit method: {0}.{1}")]
-        private void MethodExitTraceDistributed(string thisOrContextObject, string methodname)
+        private void MethodExitTraceDistributed(string thisOrContextObject, string? methodname)
         {
             SetActivityId(string.Empty);
             WriteEvent(METHOD_EXIT_DISTRIBUTED_EVENTID, thisOrContextObject, methodname);
@@ -942,7 +942,7 @@ namespace System.Transactions
         /// <summary>Trace an event when there is an internal error on transactionscope.</summary>
         /// <param name="error">The error information.</param>
         [NonEvent]
-        internal void TransactionScopeInternalError(string error)
+        internal void TransactionScopeInternalError(string? error)
         {
             if (IsEnabled(EventLevel.Critical, ALL_KEYWORDS))
             {
@@ -951,7 +951,7 @@ namespace System.Transactions
         }
 
         [Event(TRANSACTIONSCOPE_INTERNAL_ERROR_EVENTID, Keywords = Keywords.TraceBase, Level = EventLevel.Critical, Task = Tasks.TransactionScope, Opcode = Opcodes.InternalError, Message = "Transactionscope internal error: {0}")]
-        private void TransactionScopeInternalErrorTrace(string error)
+        private void TransactionScopeInternalErrorTrace(string? error)
         {
             SetActivityId(string.Empty);
             WriteEvent(TRANSACTIONSCOPE_INTERNAL_ERROR_EVENTID, error);
index 5056341..534e4ab 100644 (file)
@@ -19,8 +19,8 @@ namespace System.Transactions
         protected InternalTransaction _transaction;
 
         // Store the IVolatileEnlistment interface to call back to the Distributed TM
-        internal IPromotedEnlistment _promotedEnlistment;
-        internal IPromotedEnlistment _preparingEnlistment;
+        internal IPromotedEnlistment? _promotedEnlistment;
+        internal IPromotedEnlistment? _preparingEnlistment;
 
         public VolatileDemultiplexer(InternalTransaction transaction)
         {
@@ -32,7 +32,7 @@ namespace System.Transactions
             // Broadcast preprepare to the volatile subordinates
             for (int i = 0; i < volatiles._volatileEnlistmentCount; i++)
             {
-                volatiles._volatileEnlistments[i]._twoPhaseState.InternalCommitted(
+                volatiles._volatileEnlistments[i]._twoPhaseState!.InternalCommitted(
                     volatiles._volatileEnlistments[i]);
             }
         }
@@ -43,7 +43,7 @@ namespace System.Transactions
             // Broadcast preprepare to the volatile subordinates
             for (int i = 0; i < volatiles._volatileEnlistmentCount; i++)
             {
-                volatiles._volatileEnlistments[i]._twoPhaseState.InternalAborted(
+                volatiles._volatileEnlistments[i]._twoPhaseState!.InternalAborted(
                     volatiles._volatileEnlistments[i]);
             }
         }
@@ -53,13 +53,13 @@ namespace System.Transactions
             // Broadcast preprepare to the volatile subordinates
             for (int i = 0; i < volatiles._volatileEnlistmentCount; i++)
             {
-                volatiles._volatileEnlistments[i]._twoPhaseState.InternalIndoubt(
+                volatiles._volatileEnlistments[i]._twoPhaseState!.InternalIndoubt(
                     volatiles._volatileEnlistments[i]);
             }
         }
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
         internal static object ClassSyncObject
         {
             get
@@ -73,8 +73,8 @@ namespace System.Transactions
             }
         }
 
-        private static WaitCallback s_prepareCallback;
-        private static WaitCallback PrepareCallback => LazyInitializer.EnsureInitialized(ref s_prepareCallback, ref s_classSyncObject, () => new WaitCallback(PoolablePrepare));
+        private static WaitCallback? s_prepareCallback;
+        private static WaitCallback PrepareCallback => LazyInitializer.EnsureInitialized(ref s_prepareCallback, ref s_classSyncObject, () => new WaitCallback(PoolablePrepare!));
 
         protected static void PoolablePrepare(object state)
         {
@@ -112,8 +112,8 @@ namespace System.Transactions
             }
         }
 
-        private static WaitCallback s_commitCallback;
-        private static WaitCallback CommitCallback => LazyInitializer.EnsureInitialized(ref s_commitCallback, ref s_classSyncObject, () => new WaitCallback(PoolableCommit));
+        private static WaitCallback? s_commitCallback;
+        private static WaitCallback CommitCallback => LazyInitializer.EnsureInitialized(ref s_commitCallback, ref s_classSyncObject, () => new WaitCallback(PoolableCommit!));
 
         protected static void PoolableCommit(object state)
         {
@@ -151,8 +151,8 @@ namespace System.Transactions
             }
         }
 
-        private static WaitCallback s_rollbackCallback;
-        private static WaitCallback RollbackCallback => LazyInitializer.EnsureInitialized(ref s_rollbackCallback, ref s_classSyncObject, () => new WaitCallback(PoolableRollback));
+        private static WaitCallback? s_rollbackCallback;
+        private static WaitCallback RollbackCallback => LazyInitializer.EnsureInitialized(ref s_rollbackCallback, ref s_classSyncObject, () => new WaitCallback(PoolableRollback!));
 
         protected static void PoolableRollback(object state)
         {
@@ -190,8 +190,8 @@ namespace System.Transactions
             }
         }
 
-        private static WaitCallback s_inDoubtCallback;
-        private static WaitCallback InDoubtCallback => LazyInitializer.EnsureInitialized(ref s_inDoubtCallback, ref s_classSyncObject, () => new WaitCallback(PoolableInDoubt));
+        private static WaitCallback? s_inDoubtCallback;
+        private static WaitCallback InDoubtCallback => LazyInitializer.EnsureInitialized(ref s_inDoubtCallback, ref s_classSyncObject, () => new WaitCallback(PoolableInDoubt!));
 
         protected static void PoolableInDoubt(object state)
         {
@@ -256,6 +256,7 @@ namespace System.Transactions
 
         protected override void InternalPrepare()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
             try
             {
                 _transaction.State.ChangeStatePromotedPhase0(_transaction);
@@ -282,6 +283,8 @@ namespace System.Transactions
 
         protected override void InternalCommit()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
+
             // Respond immediately to the TM
             _promotedEnlistment.EnlistmentDone();
 
@@ -290,6 +293,8 @@ namespace System.Transactions
 
         protected override void InternalRollback()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
+
             // Respond immediately to the TM
             _promotedEnlistment.EnlistmentDone();
 
@@ -298,6 +303,7 @@ namespace System.Transactions
 
         protected override void InternalInDoubt()
         {
+            Debug.Assert(_transaction.State != null);
             _transaction.State.InDoubtFromDtc(_transaction);
         }
 
@@ -341,6 +347,7 @@ namespace System.Transactions
 
         protected override void InternalPrepare()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
             try
             {
                 _transaction.State.ChangeStatePromotedPhase1(_transaction);
@@ -368,6 +375,8 @@ namespace System.Transactions
 
         protected override void InternalCommit()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
+
             // Respond immediately to the TM
             _promotedEnlistment.EnlistmentDone();
 
@@ -377,6 +386,8 @@ namespace System.Transactions
 
         protected override void InternalRollback()
         {
+            Debug.Assert(_promotedEnlistment != null && _transaction.State != null);
+
             // Respond immediately to the TM
             _promotedEnlistment.EnlistmentDone();
 
@@ -386,6 +397,7 @@ namespace System.Transactions
 
         protected override void InternalInDoubt()
         {
+            Debug.Assert(_transaction.State != null);
             _transaction.State.InDoubtFromDtc(_transaction);
         }
 
index 1d926ee..88c9490 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Diagnostics;
 using System.Threading;
 
 namespace System.Transactions
@@ -11,19 +12,19 @@ namespace System.Transactions
     // Base class for all volatile enlistment states
     internal abstract class VolatileEnlistmentState : EnlistmentState
     {
-        private static VolatileEnlistmentActive s_volatileEnlistmentActive;
-        private static VolatileEnlistmentPreparing s_volatileEnlistmentPreparing;
-        private static VolatileEnlistmentPrepared s_volatileEnlistmentPrepared;
-        private static VolatileEnlistmentSPC s_volatileEnlistmentSPC;
-        private static VolatileEnlistmentPreparingAborting s_volatileEnlistmentPreparingAborting;
-        private static VolatileEnlistmentAborting s_volatileEnlistmentAborting;
-        private static VolatileEnlistmentCommitting s_volatileEnlistmentCommitting;
-        private static VolatileEnlistmentInDoubt s_volatileEnlistmentInDoubt;
-        private static VolatileEnlistmentEnded s_volatileEnlistmentEnded;
-        private static VolatileEnlistmentDone s_volatileEnlistmentDone;
+        private static VolatileEnlistmentActive? s_volatileEnlistmentActive;
+        private static VolatileEnlistmentPreparing? s_volatileEnlistmentPreparing;
+        private static VolatileEnlistmentPrepared? s_volatileEnlistmentPrepared;
+        private static VolatileEnlistmentSPC? s_volatileEnlistmentSPC;
+        private static VolatileEnlistmentPreparingAborting? s_volatileEnlistmentPreparingAborting;
+        private static VolatileEnlistmentAborting? s_volatileEnlistmentAborting;
+        private static VolatileEnlistmentCommitting? s_volatileEnlistmentCommitting;
+        private static VolatileEnlistmentInDoubt? s_volatileEnlistmentInDoubt;
+        private static VolatileEnlistmentEnded? s_volatileEnlistmentEnded;
+        private static VolatileEnlistmentDone? s_volatileEnlistmentDone;
 
         // Object for synchronizing access to the entire class( avoiding lock( typeof( ... )) )
-        private static object s_classSyncObject;
+        private static object? s_classSyncObject;
 
         internal static VolatileEnlistmentActive VolatileEnlistmentActive =>
             LazyInitializer.EnsureInitialized(ref s_volatileEnlistmentActive, ref s_classSyncObject, () => new VolatileEnlistmentActive());
@@ -144,6 +145,7 @@ namespace System.Transactions
                     etwLog.EnlistmentStatus(enlistment, NotificationCall.Prepare);
                 }
 
+                Debug.Assert(enlistment.EnlistmentNotification != null);
                 enlistment.EnlistmentNotification.Prepare(enlistment.PreparingEnlistment);
             }
             finally
@@ -170,11 +172,12 @@ namespace System.Transactions
         }
 
         // The enlistment says to abort start the abort sequence.
-        internal override void ForceRollback(InternalEnlistment enlistment, Exception e)
+        internal override void ForceRollback(InternalEnlistment enlistment, Exception? e)
         {
             // Change enlistment state to aborting
             VolatileEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             // Start the transaction aborting
             enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e);
 
@@ -217,6 +220,7 @@ namespace System.Transactions
             Monitor.Exit(enlistment.Transaction);
             try // Don't hold this lock while calling into the application code.
             {
+                Debug.Assert(enlistment.SinglePhaseNotification != null);
                 enlistment.SinglePhaseNotification.SinglePhaseCommit(enlistment.SinglePhaseEnlistment);
                 spcCommitted = true;
             }
@@ -235,23 +239,26 @@ namespace System.Transactions
         internal override void EnlistmentDone(InternalEnlistment enlistment)
         {
             VolatileEnlistmentEnded.EnterState(enlistment);
+            Debug.Assert(enlistment.Transaction.State != null);
             enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction);
         }
 
         internal override void Committed(InternalEnlistment enlistment)
         {
             VolatileEnlistmentEnded.EnterState(enlistment);
+            Debug.Assert(enlistment.Transaction.State != null);
             enlistment.Transaction.State.ChangeStateTransactionCommitted(enlistment.Transaction);
         }
 
-        internal override void Aborted(InternalEnlistment enlistment, Exception e)
+        internal override void Aborted(InternalEnlistment enlistment, Exception? e)
         {
             VolatileEnlistmentEnded.EnterState(enlistment);
 
+            Debug.Assert(enlistment.Transaction.State != null);
             enlistment.Transaction.State.ChangeStateTransactionAborted(enlistment.Transaction, e);
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             VolatileEnlistmentEnded.EnterState(enlistment);
 
@@ -260,6 +267,7 @@ namespace System.Transactions
                 enlistment.Transaction._innerException = e;
             }
 
+            Debug.Assert(enlistment.Transaction.State != null);
             enlistment.Transaction.State.InDoubtFromEnlistment(enlistment.Transaction);
         }
     }
@@ -324,7 +332,7 @@ namespace System.Transactions
         }
 
         // The enlistment says to abort start the abort sequence.
-        internal override void ForceRollback(InternalEnlistment enlistment, Exception e)
+        internal override void ForceRollback(InternalEnlistment enlistment, Exception? e)
         {
             // Change enlistment state to aborting
             VolatileEnlistmentEnded.EnterState(enlistment);
@@ -365,6 +373,7 @@ namespace System.Transactions
                     etwLog.EnlistmentStatus(enlistment, NotificationCall.Rollback);
                 }
 
+                Debug.Assert(enlistment.EnlistmentNotification != null);
                 enlistment.EnlistmentNotification.Rollback(enlistment.SinglePhaseEnlistment);
             }
             finally
@@ -407,6 +416,7 @@ namespace System.Transactions
                     etwLog.EnlistmentStatus(enlistment, NotificationCall.Commit);
                 }
 
+                Debug.Assert(enlistment.EnlistmentNotification != null);
                 // Forward the notification to the enlistment
                 enlistment.EnlistmentNotification.Commit(enlistment.Enlistment);
             }
@@ -440,6 +450,7 @@ namespace System.Transactions
                     etwLog.EnlistmentStatus(enlistment, NotificationCall.InDoubt);
                 }
 
+                Debug.Assert(enlistment.EnlistmentNotification != null);
                 // Forward the notification to the enlistment
                 enlistment.EnlistmentNotification.InDoubt(enlistment.PreparingEnlistment);
             }
@@ -492,7 +503,7 @@ namespace System.Transactions
             // the transaction tells it to do so
         }
 
-        internal override void InDoubt(InternalEnlistment enlistment, Exception e)
+        internal override void InDoubt(InternalEnlistment enlistment, Exception? e)
         {
             // Ignore this in case the enlistment gets here before
             // the transaction tells it to do so