Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
189 views
in Technique[技术] by (71.8m points)

c# - How to use ?? with return?

I want to return Todo object whenever there is such an object, otherwise return NotFound(). I also want to use only a single line consisting of return and ??. The following produces error at compile time. How to solve it?

public async Task<ActionResult<Todo>> GetTodo(long id)
{
    return await _context.Todos.FindAsync(id) ?? NotFound();
}

Attempt 1

enter image description here

Attempt 2

enter image description here

Attempt 3

MarTim's attempt passes the compiler,

public async Task<IActionResult> GetTodo(long id)
{
    return (IActionResult)(await _context.Todos.FindAsync(id)) ?? NotFound();
}

but generates runtime errors:

enter image description here

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Let's simplify it a bit:

public async Task<ActionResult<Todo>> GetTodo(long id)
{
    Todo todo = await _context.Todos.FindAsync(id);
    return todo ?? NotFound();
}

The problem here is that todo and NotFound() have very different types. todo is a Todo, but NotFound() returns a NotFoundResult. These two are inherently incompatible, and the compiler doesn't know that it should convert both of them to an ActionResult<Todo>.

If you want to keep the method's return type as ActionResult<Todo>, you can write:

public async Task<ActionResult<Todo>> GetTodo(long id)
{
    return (await _context.Todos.FindAsync(id)) ?? new ActionResult<Todo>(NotFound());
}

Alteratively, you can use a helper method:

public static ActionResult<T> ResultOrNotFound<T>(T item) where T : class
{
    return item != null ? new ActionResult<T>(item) : new ActionResult<T>(NotFound());
}

Then you can write:

public async Task<ActionResult<Todo>> GetTodo(long id)
{
    return ResultOrNotFound(await _context.Todos.FindAsync(id));
}

Alternatively, if you're OK with returning an IActionResult instead, then you can do:

public static IActionResult OkOrNull(object item)
{
    return item != null ? Ok(item) : null;
}

Then you can write:

public async Task<IActionResult<Todo>> GetTodo(long id)
{
    return OkOrNull(await _context.Todos.FindAsync(id)) ?? NotFound();
}

You can make this look a bit nicer if you want, with another overload:

public static async Task<IActionResult> OkOrNull<T>(Task<T> task) where T : class
{
    T item = await task;
    return item != null ? Ok(item) : null;
}

Meaning you can write:

public async Task<IActionResult<Todo>> GetTodo(long id)
{
    return await OkOrNull(_context.Todos.FindAsync(id)) ?? NotFound();
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...