简体   繁体   English

抛出异常的最佳方法

[英]The best way to throw an exception

Do you know a better way (more pretty) than below 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 extension methods: 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;
}

If it is valid to try to get the playlist for something that doesn't have a playlist, then you should not throw an exception but should just return a special value that means "not found" instead (for example, 0 or -1 depending on how your playlist IDs work). 如果尝试获取没有播放列表的播放列表是有效的,那么你不应该抛出异常,而应该只返回一个特殊的值,意思是“找不到”(例如,取决于0或-1)关于播放列表ID的工作方式)。

Alternatively you could write a TryGetPlaylistId() method which works in a similar way to Microsoft's TryXXX() methods (eg SortedList.TryGetValue() ), for example: 或者,您可以编写一个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;
}

A small problem with this approach is that you are obscuring information that might be of use when trying to diagnose issues. 这种方法的一个小问题是,您在模拟诊断问题时可能会使用的信息模糊不清。 Perhaps adding Debug.WriteLine() or some other form of logging would be of use. 也许添加Debug.WriteLine()或其他形式的日志记录是有用的。 The point being, you can't differentiate between the case where the playlist ID is not found, and the case where it is found but doesn't contain a playlist. 关键是,您无法区分未找到播放列表ID的情况和找到它但不包含播放列表的情况。

Otherwise, you could throw an exception which has a more informative message, for example: 否则,您可以抛出一个具有更多信息的异常,例如:

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;
}

It might be the case that it is valid to not find the song in the playlist, but it is NOT valid to find one which does not have a playlist, in which case you would return a special value in the first case and throw an exception in the second case, for example: 可能的情况是,在播放列表中找不到该歌曲是有效的,但找到没有播放列表的歌曲是无效的,在这种情况下,您将在第一种情况下返回特殊值并抛出异常在第二种情况下,例如:

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;
}

In any case, I personally think that your extension methods are just obscuring the code. 无论如何,我个人认为你的扩展方法只是模糊了代码。

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

return obj; 返回obj;

You should not throw error unless caught in to some. 除非陷入某些人,否则你不应该抛出错误。 Better return null in the given case and handle it in your calling code: 最好在给定的情况下返回null并在您的调用代码中处理它:

And what will happen if I have more than one such ambiguous methods in my class? 如果我班上有多个这样模棱两可的方法,会发生什么? It's very difficult to invent different rules for any method. 为任何方法制定不同的规则是非常困难的。 You will be confused in the end. 最后你会感到困惑。 What do you think about this solution? 您对此解决方案有何看法?

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
}

In such case I can send all the errors to a client. 在这种情况下,我可以将所有错误发送给客户端。

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

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