Я пишу свое первое приложение с использованием минимальных API в приложении .NET 8. Я выполняю обучающее упражнение, которое нашел в Microsoft Learn, и использую разработанную мной базу данных. Я столкнулся с этой ошибкой:
CS0311 Тип «Show1» нельзя использовать в качестве параметра типа. «TImplementation» в универсальном типе или методе 'ServiceCollectionServiceExtensions.AddScoped<TService, TImplementation>(IServiceCollection)». Нет неявной ссылки преобразование из «Show1» в «BlazorMediaLibrary.API.Interfaces.IShow1»
Я искал эту ошибку и придумал Почему ограничение общего типа приводит к ошибке неявного преобразования ссылок? здесь, на ТАК. Однако я не думаю, что это соответствует моей ситуации. Вот что я получил для своего интерфейса, который был сгенерирован, когда я формировал базу данных для создания классов модели и DbContext:
public interface IShow1
{
int ShowId { get; set; }
int ShowCode { get; set; }
string EpisodeName { get; set; }
string? Synopsis { get; set; }
DateTime? DateLastViewed { get; set; }
DateTime? OriginalBroadcastDate { get; set; }
TimeOnly? PlayTime { get; set; }
double? Rating { get; set; }
TypeOfShow1 ShowCodeNavigation { get; set; }
ICollection<Entries2> Entries2s { get; set; }
ICollection<UserRating> UserRatings { get; set; }
}
и вот реализация класса модели:
public partial class Show1 : IShow1
{
public int ShowId { get; set; }
public int ShowCode { get; set; }
public string EpisodeName { get; set; } = null!;
public string? Synopsis { get; set; }
public DateTime? DateLastViewed { get; set; }
public DateTime? OriginalBroadcastDate { get; set; }
public TimeOnly? PlayTime { get; set; }
public double? Rating { get; set; }
public virtual TypeOfShow1 ShowCodeNavigation { get; set; } = null!;
public virtual ICollection<Entries2> Entries2s { get; set; } = new List<Entries2>();
public virtual ICollection<UserRating> UserRatings { get; set; } = new List<UserRating>();
}
В файле Program.cs я определил эту запись:
internal record Show1(int ShowId, int ShowCode, string EpisodeName,
string? Synopsis, DateTime? DateLastViewed,
DateTime? OriginalBoardcastDate, TimeOnly? PlayTime, float? Rating);
А вот строка в Program.cs, которая вызывает ошибку:
builder.Services.AddScoped<IShow1, Show1>();
Я не включил ShowCodeNavigation, Entries2 или UserRatings в определение записи в Program.cs.
Это причина моей проблемы?
Когда я навожу указатель мыши на IShow1 в классе Show1 в папке «Модели», он указывает на интерфейс в BlazorMediaLibrary.API.Interfaces. В файле Program.cs интерфейс IShow1, используемый в builder.Services.AddScoped(), также указывает интерфейс в BlazorMediaLibrary.API.Interfaces. А класс Show1 в том же builderr.Services.AddScoped() указывает на класс Show1 в папке Models.
Ради ухмылки и смеха я решил закомментировать два оператора using в верхней части файла Program.cs, а затем заменил builder.Services.AddScoped на это: builder.Services.AddScoped<BlazorMediaLibrary.API.Interfaces .IShow1, BlazorMediaLibrary.API.Models.Show1>(); Это устранило ошибки. Я не понимаю, почему это устранило ошибки.
Я пропустил, что вы также определили запись под названием Show1. Я сильно подозреваю, что проблема была в этом — обратите внимание, что в сообщении об ошибке речь идет не о BlazorMediaLibrary.API.Models.Show1, а только о Show1. Помимо всего прочего, наличие и класса, и записи с именем Show1 могло бы сбить с толку любого человека, работающего с кодом...





В файле Program.cs я определил такую запись:
internal record Show1...
Он будет «затенять» Show1, который реализует интерфейс, и «импортируется» через соответствующий оператор using. Я бы порекомендовал переименовать record во что-нибудь другое, но если есть очень веская причина иметь как внутреннюю запись, так и класс с одним и тем же именем (я не могу придумать ни одного, но все же), вы можете использовать «полный» тип. имя для регистрации:
builder.Services.AddScoped<IShow1, BlazorMediaLibrary.API.Models.Show1>();
Если запись не используется в коде оператора верхнего уровня (т. е. в Program.cs), вы можете переключиться на «явный» метод Main (см. Должны ли директивы using находиться внутри или снаружи пространства имен в C#? для возможного объяснения):
namespace MyNamespace
{
using BlazorMediaLibrary.API.Models; // moving import out of the namespace will break the compilation
public class Program
{
public void Main()
{
new ServiceCollection()
.AddScoped<IShow1, Show1>();
}
}
}
internal record Show1(int ShowId, ...);
или перемещение записи в какое-то пространство имен:
// in Program.cs
app.Run();
namespace MyNamespace
{
internal record Show1(...);
}
В вашем текущем коде internal record Show1 приводит к классу записи, сгенерированному в глобальном пространстве имен, что приводит к поведению, которое вы наблюдаете.
Спасибо вам за разъяснение! Я хотел знать, что происходит и почему. Я ценю это.
Вы абсолютно уверены, что интерфейс
IShow1, реализуемый вашим классом, тот же самый, который вы пытаетесь использовать, т. е.BlazorMediaLibrary.API.Interfaces.IShow1? Если вы поместите курсор вIShow1в объявлении класса (где вы заявляете, что реализуете его) и нажмете F12, к какому интерфейсу он перейдет?