Имея объект, который реализует интерфейс со статическим методом, как я могу вызвать этот статический метод?
Обратите внимание, что я не хочу добавлять TRequest к общей подписи, я имитирую IMediatR.
Это ошибка, которую я получаю: CS0176 Member 'IApiRequest<TResponse>.GetRequestPath()' cannot be accessed with an instance reference; qualify it with a type name instead
internal class Program
{
static void Main(string[] args)
{
var request = new GetAdditionalUserClaimsQuery();
Execute(request);
}
public static void Execute<TResponse>(IApiRequest<TResponse> request)
{
// How do I call GetRequestPath here?
string requestPath = ((IApiRequest<TResponse>)request).GetRequestPath();
}
public interface IApiRequest<TResponse>
{
static abstract string GetRequestPath();
}
public class GetAdditionalUserClaimsQuery : IApiRequest<GetAdditionalUserClaimsResponse>
{
public static string GetRequestPath() => "accounts/get-additional-user-claims";
}
public class GetAdditionalUserClaimsResponse
{
}
}
Вы уверены, что ваш GetRequestPath должен быть static? Для меня это больше похоже на то, что вы вызываете экземпляр request (как вы все равно сейчас пытаетесь), чем на класс
Мне нужно вызвать его статически на сервере, чтобы зарегистрировать конечные точки API, и на экземплярах в клиенте, чтобы определить, куда звонить, поэтому мне нужно и то, и другое.
Статические методы не нуждаются в экземпляре, поэтому вы можете передать null. Используя отражение, это работает.
public static void Execute<TResponse>(IApiRequest<TResponse> request)
{
var requestType = request.GetType();
var method = requestType.GetMethod("GetRequestPath", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public);
var result = method?.Invoke(null, new object[] { });
}
Раньше у меня были проблемы с этим в WASM, но сегодня утром я попробовал, и это сработало. Спасибо!
Вы также можете просто передать null для параметров вместо создания нового пустого массива. (Или Array.Empty<object>(), если вам действительно нужно передать массив.)
Поскольку несколько типов могут реализовать IApiRequest<TResponse>, вам нужно добавить еще один общий параметр, чтобы ваш метод знал, какой тип реализует IApiRequest<TResponse> для этого вызова;
public static void Execute<TRequest,TResponse>(TRequest request) where TRequest : IApiRequest<TResponse>{
... TRequest.GetRequestPath();
}
Обратите внимание, что это позволяет вызывающему абоненту совершить ошибку, например;
public class AnotherType : GetAdditionalUserClaimsQuery{
public static string GetRequestPath() => ... ;
}
Program.Execute<GetAdditionalUserClaimsQuery, GetAdditionalUserClaimsResponse>(new AnotherType());
Возможно, вы захотите добавить этот дополнительный параметр в свой интерфейс и запечатать свои реализации;
public interface IApiRequest<TRequest, TResponse> where TRequest : IApiRequest<TRequest, TResponse> {}
public sealed class GetAdditionalUserClaimsQuery : IApiRequest<GetAdditionalUserClaimsQuery, GetAdditionalUserClaimsResponse> {}
Я не хочу этого делать, потому что тогда мне придется указывать оба универсальных типа всякий раз, когда я вызываю метод, тогда как в данный момент он может его вывести. Это тот же подход, что и mediatr.
Думайте об этом как об обычном статическом методе. Как вы можете вызвать общедоступный статический метод для экземпляра? Вы не можете... вы должны полностью квалифицировать статический вызов (также известный как GetAdditionalUserClaimsQuery.GetRequestPath();. То же самое применимо и здесь.