2014-03-12 9 views
5

Ich habe eine UserScope Klasse, die ähnlich wie TransactionScope funktioniert, d. H. Es speichert den aktuellen Zustand in einem lokalen Thread. Dies funktioniert natürlich nicht über Aufrufe an await, und auch TransactionScope bis TransactionScopeAsyncFlowOption wurde in .NET 4.5.1 hinzugefügt.Sharing Bereich über erwartet

Welche Alternative zu lokalen Thread kann ich verwenden, so dass UserScope die gleiche in Singlethread-und Multithread-Szenarien verwendet werden kann? (Wenn ich 4.5.1 installiert hätte, würde ich decompile zu sehen, wie TransactionScope tut es.) Dies ist eine vereinfachte Version von dem, was ich habe:

class User { 
    readonly string name; 

    public User(string name) { 
     this.name = name; 
    } 

    public string Name { 
     get { return this.name; } 
    } 
} 

class UserScope : IDisposable { 
    readonly User user; 

    [ThreadStatic] 
    static UserScope currentScope; 

    public UserScope(User user) { 
     this.user = user; 
     currentScope = this; 
    } 

    public static User User { 
     get { return currentScope != null ? currentScope.user : null; } 
    } 

    public void Dispose() { 
     ///... 
    } 
} 

Und das ist ein Test, den ich erwarten würde zu arbeiten:

static async Task Test() { 
    var user = new User("Thread Flintstone"); 
    using (new UserScope(user)) { 
     await Task.Run(delegate { 
      Console.WriteLine("Crashing with NRE..."); 
      Console.WriteLine("The current user is: {0}", UserScope.User.Name); 
     }); 
    } 
} 

static void Main(string[] args) { 
    Test().Wait(); 
    Console.ReadLine(); 
} 
+2

Sie müssen .NET 4.5.1 nicht installiert haben, um in die Quellen zu schauen. Geben Sie ["Ein neues Aussehen für die .NET-Referenzquelle"] ein (http://blogs.msdn.com/b/dotnet/archive/2014/02/24/a-new-look-for-net-reference-source). aspx). Insbesondere ['TransactionScope'] (http://referencesource.microsoft.com/#System.Transactions/NetFx20/System.Transactions/System/Transactions/TransactionScope.cs#988b00261b7ce735). Ich * wirklich * mag es, gut gemacht, Microsoft :) – Noseratio

+1

@Noseratio: Super. Ich werde das überprüfen. Vielen Dank. – Daniel

Antwort

6

in .NET 4.5 voll Framework können Sie den logischen Anrufkontext für diesen Einsatz:

static async Task Test() 
{ 
    CallContext.LogicalSetData("Name", "Thread Flintstone"); 
    await Task.Run(delegate 
    { 
     //Console.WriteLine("Crashing with NRE..."); 
     Console.WriteLine("The current user is: {0}", CallContext.LogicalGetData("Name")); 
    }); 
} 

static void Main(string[] args) 
{ 
    Test().Wait(); 
    Console.ReadLine(); 
} 

Sie sollten jedoch nur unveränderliche Daten speichern im logischen Anrufkontext. Ich habe more details on my blog. Ich wollte das in eine AsyncLocal<T> Bibliothek einpacken, habe aber (noch) nicht die Zeit gefunden.

+0

Sehr nett! Vielen Dank. – Daniel