让我说我有这样的安排:
public interface ICreatable
{
int CreatedByUserId { get; set; }
}
public class Unicorn : ICreatable
{
public int CreatedByUserId { get; set; }
}
public interface ICrudService<T>
where T : class, ICreatable
{
T DoSomething(T t);
}
public class UnicornService : ICrudService<Unicorn>
{
public Unicorn DoSomething(Unicorn unicorn)
{
var createdByUserId = unicorn.CreatedByUserId;
// ...
return unicorn;
}
}
并像这样使用它:
static void Main(string[] args)
{
var unicorn = new Unicorn();
var unicornService = new UnicornService();
unicornService.DoSomething(unicorn);
}
这很好。但是,假设我想将unicornService
作为ICrudService
的接口类型以及它的通用类型转换为它的接口类型:
var crudService = unicornService as ICrudService<ICreatable>;
我遇到了问题。这是它的外观:
unicornService as ICrudService<Unicorn> --> casts is fine
unicornService as ICrudService<ICreatable> --> casts to null
似乎Unicorn
ICreatable
来自ICrudService<T> where T: class, ICreatable
,而crudService
以来,它应该没有问题。我的搜索开始引导我进入Covariance和Contravariances,但我在那个级别迷路了。
如何将ICrudService<ICreatable>
投射到 public interface ICrudService<out T>
?
更新
使用协方差:
{{1}}
然后使intellisense说“无效的方差:类型参数'T'必须在'ICrudService.DoSomething(T)'上有效。”T'是协变的。“这是如何工作的?
答案 0 :(得分:0)
ICrudService<Unicorn>
不能视为ICrudService<ICreatable>
。
ICrudService<Unicorn>
对象只允许接受Unicorn
类型的参数或Unicorn
的子类型,但ICrudService<ICreatable>
可以接受SomeOtherTypeOfICreatable
的参数。
您UnicornService
类型允许使用特定于Unicorn
的成员,而不仅仅是ICreatable
,因为这是它限制其功能的类型。该限制禁止它满足更通用的接口API。
因此,简而言之,这是不可能的。
答案 1 :(得分:0)
您应该将DoSomething更改为接受可强制使用而不是T来使用 out T 修饰符:
public interface ICrudService<out T>
where T : class, ICreatable
{
T DoSomething(ICreatable t);
}
public class UnicornService : ICrudService<Unicorn>
{
public Unicorn DoSomething(ICreatable t)
{
var unicorn = (Unicorn)t;
var createdByUserId = unicorn.CreatedByUserId; // or t.CreatedByUserId
// ...
return unicorn;
}
}
请注意,如果非Unicorn将传递给UnicornService,此代码将抛出异常。