r3plica
r3plica

Reputation: 13387

Generic method with HttpMethod as a parameter

I am trying to create a method that will invoke other methods based on the HttpMethod. My method looks like this:

public async Task<string> CreateAsync<T>(HttpClient client, string url, HttpMethod method, T data, Dictionary<string, string> parameters = null)
{
    switch(method)
    {
        case HttpMethod.Post:
            return await PostAsync(client, url, data);
        case HttpMethod.Put:
            return await PutAsync(client, url, data);
        case HttpMethod.Delete:
            return await DeleteAsync(client, url, parameters);
        default:
            return await GetAsync(client, url, parameters);
    }
}

The problem is, the switch is moaning about this:

A constant value is expected

And each case is underlined in red. Does anyone know what I am doing wrong?

Upvotes: 14

Views: 6543

Answers (3)

gregkalapos
gregkalapos

Reputation: 3619

As it was already pointed out the problem is that the HttpMethod Delete, Post, ...etc. properties are instances and not constants or enums. It was also pointed out that they are equatable.

The only thing I would like to add is that if this is C# 7 you can use pattern matching instead of the if..else if....else if... chain:

public async Task<string> CreateAsync<T>(HttpClient client, string url, HttpMethod method, T data, Dictionary<string, string> parameters = null)
{
    switch (method)
    {
        case HttpMethod m when m == HttpMethod.Post:
            return await PostAsync(client, url, data);
        case HttpMethod m when m == HttpMethod.Put:
            return await PutAsync(client, url, data);
        case HttpMethod m when m == HttpMethod.Delete:
            return await DeleteAsync(client, url, parameters);
        default:
            return await GetAsync(client, url, parameters);
    }
}

Upvotes: 18

Win
Win

Reputation: 62290

You could not do that like dasblinkenlight and Nkosi said. The easiest work around is to use HttpMethod.Method and hard-coded string for case statement.

public async Task<string> CreateAsync<T>(HttpClient client, string url, HttpMethod method, T data, Dictionary<string, string> parameters = null)
{
    switch (method.Method)
    {
        case "POST":
            return await PostAsync(client, url, data);
        case "PUT":
            return await PutAsync(client, url, data);
        case "DELETE":
            return await DeleteAsync(client, url, parameters);
        default:
            return await GetAsync(client, url, parameters);
    }
}

Upvotes: 4

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726889

Since static properties of HttpMethod, such as HttpMethod.Put and HttpMethod.Post, are instances of HttpMethod class, you cannot use them as case expressions in a switch statement, as if they were members of an enum.

These objects are equatable, though, so you can use them in a chain of if-then-else, or in a Dictionary<HttpMethod,SomeDelegate> where SomeDelegate is an action type representing the task that you would like to run:

if (method == HttpMethod.Post) {
    return await PostAsync(client, url, data);
} else if (method == HttpMethod.Put) {
    return await PutAsync(client, url, data);
} else if (method == HttpMethod.Delete) {
    return await DeleteAsync(client, url, parameters);
} else {
    return await GetAsync(client, url, parameters);
}

Upvotes: 2

Related Questions