我在下面有以下代码。我有两个主要接口(interface)IWatch
和 IWatchService
.原来Watch()
在IWatchService
并且没有 IWatch
但自那以后CollectionService
不能使用 Watch()
我决定 ( ISP
) 创建 IWatch
的方法接口(interface)另外。在CollectionService
我想要 ctor pass DatabaseWatchService
或 RemoteFilesWatchService
因此,我将参数类型作为 IWatchService<IEntity> watchService
放在 ctor 中然而当在DoIt()
方法初始化 fileWatcherServiceCsv
它说的变量:
Cannot implicitly convert type 'RemoteFilesWatchService' to 'IWatchService'. An explicit conversion exists (are you missing a cast?)
public interface IWatch
{
void Watch();
}
public interface IWatchService<TDataEntity> where TDataEntity : IEntity
{
INotificationFactory NotificationFactory { get; }
ObservableCollection<TDataEntity> MatchingEntries { get; set; }
}
public interface IDatabaseWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IDatabaseEntity
{
IDatabaseRepository<IDbManager> DatabaseRepository { get; }
}
public interface IRemoteFilesWatchService<TDataEntity> : IWatchService<TDataEntity> where TDataEntity : IFileEntity
{
List<string> ExistingRemoteFiles { get; set; }
List<RemoteLocation> RemoteLocations { get; set; }
IWinScpOperations RemoteManager { get; set; }
IRemoteFilesRepository<IDbManager, TDataEntity> RemoteFilesRepository { get; }
}
public class RemoteFilesWatchService : IRemoteFilesWatchService<IFileEntity>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<IFileEntity> MatchingEntries { get; set; }
public List<string> ExistingRemoteFiles { get; set; }
public List<RemoteLocation> RemoteLocations { get; set; }
public IWinScpOperations RemoteManager { get; set; }
public IRemoteFilesRepository<IDbManager, IFileEntity> RemoteFilesRepository { get; }
public RemoteFilesWatchService(IWinScpOperations remoteOperator,
IRemoteFilesRepository<IDbManager, IFileEntity> remoteFilesRepository,
INotificationFactory notificationFactory)
{
RemoteManager = remoteOperator;
RemoteFilesRepository = remoteFilesRepository; //csv, xml or other repo could be injected
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class DatabaseWatchService : IDatabaseWatchService<DatabaseQuery>, IWatch
{
public INotificationFactory NotificationFactory { get; }
public ObservableCollection<DatabaseQuery> MatchingEntries { get; set; }
public IDatabaseRepository<IDbManager> DatabaseRepository { get; }
public DatabaseWatchService(IDatabaseRepository<IDbManager> databaseRepository,
INotificationFactory notificationFactory)
{
DatabaseRepository = databaseRepository;
NotificationFactory = notificationFactory;
}
public void Watch()
{
}
}
public class CollectionService
{
private IWatchService<IEntity> _watchService;
public CollectionService(IWatchService<IEntity> watchService)
{
_watchService = watchService;
}
}
class Run
{
void DoIt()
{
IWatchService<IEntity> fileWatcherServiceCsv = new RemoteFilesWatchService(new WinScpOperations(),
new RemoteCsvFilesRepository(new DbManager(ConnectionDbType.MySql)),
new NotificationFactory());
var coll1 = new CollectionService(fileWatcherServiceCsv);
}
}
public interface IEntity
{
}
public interface IFileEntity : IEntity
{
int Id { get; set; }
string Name { get; set; }
bool IsActive { get; set; }
bool RemoveFromSource { get; set; }
string DestinationFolder { get; set; }
RemoteLocation RemoteLocation { get; set; }
}
public interface IDatabaseEntity : IEntity
{
}
public class CsvFile : IFileEntity
{
public int ColumnHeader { get; set; }
public int ColumnsCount { get; set; }
public string Separator { get; set; }
public int ValuesRowStartposition { get; set; }
public int ColumnRowPosition { get; set; }
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
}
public class XmlFile : IFileEntity
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public bool RemoveFromSource { get; set; }
public string DestinationFolder { get; set; }
public RemoteLocation RemoteLocation { get; set; }
public string SubNode { get; set; }
public string MainNode { get; set; }
}
最佳答案
这个问题几乎每天都会被发布。再来一次!
一盒苹果不是一盒水果。为什么不呢?
你可以把一根香蕉放进一盒水果里,但你不能把一根香蕉放进一盒苹果里,所以一盒苹果不是一盒水果,因为你能对它们进行的操作是不同的。同样,一盒水果不是一盒苹果。
您正在尝试使用 IWatchService
(盒)IFileEntity
(苹果)作为 IWatchService
的 IEntity
(水果),这是不合法的。
现在,您可能会注意到在 C# 中您可以使用 IEnumerable<Apple>
哪里有IEnumerable<Fruit>
是期待。这很好用,因为 没有办法将香蕉放入 IEnumerable<Fruit>
中。在IEnumerable<T>
的每个成员中和 IEnumerator<T>
, T
出来,而不是进来。
如果您处于那种情况,那么您可以将您的界面标记为
interface IWatchService<out T> ...
并且编译器将验证每个T
在界面中使用在“out”位置,然后将允许您想要的转换。
该转换称为通用协变转换,它仅在以下情况下有效:
- 泛型是接口(interface)或委托(delegate)
- 类型参数标记为
out
, 编译器验证它是安全的 - 变体类型(比如 Fruit 和 Apple)都是引用类型。例如,您不能进行涉及 int 和对象的协变转换。
关于c# - 接口(interface)不能隐式转换类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55357270/