繁体   English   中英

抛出异常的最佳方法

[英]The best way to throw an exception

你知道一个比下面更好的方式(更漂亮)抛出异常吗?

public long GetPlaylistId(long songInPlaylistId)
{
    var songInPlaylist = service.GetById(songInPlaylistId);
    return songInPlaylist
            .With(x => x.Playlist)
            .ReturnValueOrException(x => x.Id, 
                                         new ArgumentException(
                                             "Bad argument 'songInPlaylistId'"));
}

Monadic扩展方法:

public static TResult With<TInput, TResult>(this TInput obj, 
                                            Func<TInput, TResult> evaluator)
    where TInput : class
    where TResult : class
{
    return obj == null ? null : evaluator(obj);
}

public static TResult ReturnValueOrException<TInput, TResult>(
    this TInput obj, Func<TInput, TResult> evaluator, Exception exception)
    where TInput : class
{
    if (obj != null)
    {
        return evaluator(obj);
    }

    throw exception;
}

如果尝试获取没有播放列表的播放列表是有效的,那么你不应该抛出异常,而应该只返回一个特殊的值,意思是“找不到”(例如,取决于0或-1)关于播放列表ID的工作方式)。

或者,您可以编写一个TryGetPlaylistId()方法,该方法的工作方式与Microsoft的TryXXX()方法类似(例如SortedList.TryGetValue() ),例如:

public bool TryGetPlaylistId(long songInPlaylistId, out long result)
{
    result = 0;
    var songInPlaylist = service.GetById(songInPlaylistId);

    if (songInPlaylist == null)
        return false;

    if (songInPlaylist.Playlist == null)
        return false;

    result = songInPlaylist.Playlist.Id;
    return true;
}

这种方法的一个小问题是,您在模拟诊断问题时可能会使用的信息模糊不清。 也许添加Debug.WriteLine()或其他形式的日志记录是有用的。 关键是,您无法区分未找到播放列表ID的情况和找到它但不包含播放列表的情况。

否则,您可以抛出一个具有更多信息的异常,例如:

public long GetPlaylistId(long songInPlaylistId)
{
    var songInPlaylist = service.GetById(songInPlaylistId);

    if (songInPlaylist == null)
        throw new InvalidOperationException("songInPlaylistId not found: " + songInPlaylistId);

    if (songInPlaylist.Playlist == null)
        throw new InvalidOperationException("Playlist for ID " + songInPlaylistId " has no playlist: ");

    return songInPlaylist.Playlist.Id;
}

可能的情况是,在播放列表中找不到该歌曲是有效的,但找到没有播放列表的歌曲是无效的,在这种情况下,您将在第一种情况下返回特殊值并抛出异常在第二种情况下,例如:

public long GetPlaylistId(long songInPlaylistId)
{
    var songInPlaylist = service.GetById(songInPlaylistId);

    if (songInPlaylist == null)
        return -1; // -1 means "playlist not found".

    if (songInPlaylist.Playlist == null)
        throw new InvalidOperationException("Playlist for ID " + songInPlaylistId " has no playlist: ");

    return songInPlaylist.Playlist.Id;
}

无论如何,我个人认为你的扩展方法只是模糊了代码。

try{
if (obj != null)
{
    return evaluator(obj);
}
}
catch(Exception ex)
{
throw;
}

返回obj;

除非陷入某些人,否则你不应该抛出错误。 最好在给定的情况下返回null并在您的调用代码中处理它:

如果我班上有多个这样模棱两可的方法,会发生什么? 为任何方法制定不同的规则是非常困难的。 最后你会感到困惑。 您对此解决方案有何看法?

public class ApplicationResponse
{
    public IList<string> Errors { get; set; }
    public dynamic Data { get; set; }

    public bool HasErrors()
    {
        return Errors != null && Errors.Any();
    }
}

public ApplicationResponse GetPlaylistId(long songInPlaylistId)
{
    var songInPlaylist = service.GetById(songInPlaylistId);
    if (songInPlaylist == null)
    {
        return new ApplicationResponse { Errors = new[] { "Song was not found." } };
    }

    if (songInPlaylist.Playlist == null)
    {
        return new ApplicationResponse { Errors = new[] { "Playlist was not found." } };
    }

    return new ApplicationResponse { Data = songInPlaylist.Playlist.Id };
}

public HttpResponseMessage SomeRequest([FromUri] songInPlaylistId)
{
    var response = appService.GetPlaylistId(long songInPlaylistId);
    if (response.HasErrors())
    {
        // reply with error status
    }

    // reply with ok status
}

在这种情况下,我可以将所有错误发送给客户端。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM