Luk*_*ett 4 c# design-patterns asynchronous async-await c#-5.0
我经常使用TryDoSomething完全像这样的模式:
GameContext gameContext;
if (gamesRepository.TryLoadLastGame(out gameContext))
{
// Perform actions with gameContext instance.
}
else
{
// Create a new game or go to home screen or whatever.
}
Run Code Online (Sandbox Code Playgroud)
这允许良好的可读流程,但也允许成功状态,true但返回空值,该值有时对于传达“我能够得到你的东西但实际上为空”很有用。
使用async-await,异步低级API“强制”调用API以执行正确的操作并异步工作。但是,没有out参数,此模式将不起作用。
如何实现?
我有一个答案,并且正在回答问/答样式,以了解其他人对此的看法。
到目前为止,我已经使用了一个小类Attempt<T>:
public sealed class Attempt<T>
{
/// <summary>
/// Initializes a new instance of the <see cref="Attempt{T}"/> class.
/// </summary>
public Attempt() { }
/// <summary>
/// Initializes a new instance of the <see cref="Attempt{T}"/> class.
/// </summary>
public Attempt(Exception exception)
{
this.Exception = exception;
}
/// <summary>
/// Initializes a new instance of the <see cref="Attempt{T}"/> class.
/// </summary>
/// <param name="result">The result.</param>
public Attempt(T result)
{
this.Result = result;
this.HasResult = true;
}
/// <summary>
/// Gets the result.
/// </summary>
/// <value>The result.</value>
public T Result { get; private set; }
/// <summary>
/// Determines whether this instance has result.
/// </summary>
/// <returns><c>true</c> if this instance has result; otherwise, <c>false</c>.</returns>
public bool HasResult { get; private set; }
/// <summary>
/// Returns the result with a true or false depending on whether its empty, but throws if there is an exception in the attempt.
/// </summary>
/// <param name="result">The result, which may be null.</param>
/// <returns><c>true</c> if the specified result has a value; otherwise, <c>false</c>.</returns>
/// <exception cref="System.AggregateException">The attempt resulted in an exception. See InnerExceptions.</exception>
public bool TryResult(out T result)
{
if (this.HasResult)
{
result = this.Result;
return true;
}
else
{
if (this.Exception != null)
{
throw new AggregateException("The attempt resulted in an exception. See InnerExceptions.", this.Exception);
}
else
{
result = default(T);
return false;
}
}
}
/// <summary>
/// Gets or sets the exception.
/// </summary>
/// <value>The exception.</value>
public Exception Exception { get; private set; }
}
Run Code Online (Sandbox Code Playgroud)
在像这样的Try方法中使用它:
internal async Task<Attempt<T>> TryReadObjectAsync<T>(string folderName, string fileName)
{
if (String.IsNullOrWhiteSpace(folderName))
throw new ArgumentException("The string argument is null or whitespace.", "folderName");
if (String.IsNullOrWhiteSpace(fileName))
throw new ArgumentException("The string argument is null or whitespace.", "fileName");
try
{
StorageFolder folder = this.StorageFolder;
if (folderName != @"\")
folder = await StorageFolder.GetFolderAsync(folderName);
var file = await folder.GetFileAsync(fileName);
var buffy = await FileIO.ReadBufferAsync(file);
string xml = await buffy.ReadUTF8Async();
T obj = await Evoq.Serialization.DataContractSerializerHelper.DeserializeAsync<T>(xml);
return new Attempt<T>(obj);
}
catch (FileNotFoundException fnfe)
{
// Only catch and wrap expected exceptions.
return new Attempt<T>(fnfe);
}
}
Run Code Online (Sandbox Code Playgroud)
并且像这样被消耗:
DataContractStorageSerializer xmlStorage = new DataContractStorageSerializer(this.StorageFolder);
var readAttempt = await xmlStorage.TryReadObjectAsync<UserProfile>(userName, UserProfileFilename);
try
{
UserProfile user;
if (readAttempt.TryResult(out user))
{
// Do something with user.
}
else
{
// No user in the persisted file.
}
}
catch (Exception ex)
{
// Some unexpected, unhandled exception happened.
}
Run Code Online (Sandbox Code Playgroud)
或者,忽略错误。
...
var readAttempt = await xmlStorage.TryReadObjectAsync<UserProfile>(userName, UserProfileFilename);
if (readAttempt.HasResult)
{
// Continue.
this.DoSomethingWith(readAttempt.Result);
}
else
{
// Create new user.
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
269 次 |
| 最近记录: |