c#类型推断-错误-没有隐含的引用转换

本文关键字:转换 引用 类型 错误 | 更新日期: 2023-09-27 18:10:30

我有一个方法,该方法循环遍历指南列表并通过DbContext将它们保存到数据库中。B是WebObjects的DbSet集合(例如:DbSet<MlaPerson> MlaPersons)

protected void AddRelatedWebObject<A, B>(A mlaObject, B inputObject, List<Guid> guids) 
    where A : WebObject 
    where B : DbSet<WebObject>
{
    foreach (Guid guid in guids)
    {
        mlaObject.RelatedWebObjects.Add(inputObject.Find(guid));
        _db.SaveChanges();
    }
}
使用

:

foreach (ArticleRelationships item in articleRelationships)
{
    MlaArticle article = new MlaArticle();
    article = _db.MlaArticles.Include(m => m.WebSite).Where(m => m.Id == item.ArticleId).First();
    AddRelatedWebObject<MlaArticle, DbSet<MlaPerson>>(article, _db.MlaPersons, item.PersonIds);
}

_db。定义为:

public class ECM2Context : DbContext
{
    public DbSet<MlaPerson> MlaPersons { get; set; }
}

和MlaPerson定义为:

public class MlaPerson : WebObject, IValidatableObject
{
    ...
}

我认为,通过推断B是DbSet<WebObject>将工作,因为MlaPerson的基类是WebObject,但我错了。我得到错误:

The type 'System.Data.Entity.DbSet<ExternalContentManager.Models.MlaPerson>' cannot be used as a type parameter 'B' in the generic type or method 'AddRelatedWebObjects'. There is not implicit reference conversion from 'System.Data.Entity.DbSet<ExternalContentManager.Models.MlaPerson>' to 'System.Data.Entity.DbSet<ExternalContentManager.Models.WebObject>'

我将非常感谢任何和所有的帮助提供。谢谢你的帮助。B

c#类型推断-错误-没有隐含的引用转换

你犯了一个常见的泛型错误——假设集合是协变的。也就是说,即使car继承了vehicle, List<Car>的实例也不会继承List<Vehicle>。同样地,即使MlaPerson继承了WebObject, DbSet<MlaPerson>也不会继承DbSet<WebObject>

你需要做的是这样的事情(我还没有测试过这段代码):

protected void AddRelatedWebObject<A, B, O>(A mlaObject, B inputObject, List<Guid> guids) 
    where A : WebObject 
    where B : DbSet<O>
    where O : WebObject
{
    foreach (Guid guid in guids)
    {
        mlaObject.RelatedWebObjects.Add(inputObject.Find(guid));
        _db.SaveChanges();
    }
}

并这样使用:

foreach (ArticleRelationships item in articleRelationships)
{
    MlaArticle article = new MlaArticle();
    article = _db.MlaArticles.Include(m => m.WebSite).Where(m => m.Id == item.ArticleId).First();
    AddRelatedWebObject<MlaArticle, DbSet<MlaPerson>, MlaPerson>(article, _db.MlaPersons, item.PersonIds);
}

如果你这样做,你可以放弃类型规范(<MlaArticle, DbSet<MlaPerson>, MlaPerson>),因为它应该推断它。

DbSet<MlaPerson>不是DbSet<WebObject>,因为MlaPerson来自WebObject。在Stack Overflow上搜索"通用方差"可以找到很多原因。

你可能想要像这样改变你的方法参数和约束:

protected void AddRelatedWebObject<A, B>(A mlaObject, DbSet<B> inputObject,
                                         List<Guid> guids) 
    where A : WebObject 
    where B : WebObject

然后像这样调用它:

AddRelatedWebObject<MlaArticle, MlaPerson>(article, _db.MlaPersons,
                                           item.PersonIds);

这可以工作-它甚至可以与类型推断一起工作以允许:

AddRelatedWebObject(article, _db.MlaPersons, item.PersonIds);

我将建议您将类型参数重命名为TSourceTTarget之类的东西,以便更清晰,并遵循约定。

——编辑——这个答案是错误的。查看注释获取更多信息——

上转换不适用于容器(除非您正在上转换数据结构,但这里不是这种情况)。想象一下下面的代码(为了简单起见,使用数组编写,但同样的原则适用于所有泛型容器):

class A{}
class B:A{}
/*Inside a method*/
B[] arrayB=new B[10];
A[] arrayA=arrayB;//This line will produce a compile error
arrayA[0]=new A();

现在arrayB[0]包含A类型的对象,即使它的A不是B的派生类。