c#类型推断-错误-没有从

c#类型推断-错误-没有从,c#,type-inference,C#,Type Inference,我有一个方法,可以循环浏览guid列表,并通过DbContext将它们保存到数据库中。B是WebObjects的DbSet集合(例如:DbSet-mlaperson) 我认为通过推断B是DbSet会起作用,因为MlaPerson的基类是WebObject,但我错了。我得到了一个错误: 类型“System.Data.Entity.DbSet”不能用作泛型类型或方法“AddRelatedWebObjects”中的类型参数“B”。没有从“System.Data.Entity.DbSet”到“Syste

我有一个方法,可以循环浏览guid列表,并通过DbContext将它们保存到数据库中。B是WebObjects的DbSet集合(例如:
DbSet-mlaperson

我认为通过推断B是DbSet
会起作用,因为MlaPerson的基类是WebObject,但我错了。我得到了一个错误:

类型“System.Data.Entity.DbSet”不能用作泛型类型或方法“AddRelatedWebObjects”中的类型参数“B”。没有从“System.Data.Entity.DbSet”到“System.Data.Entity.DbSet”的隐式引用转换

我真的非常感谢所有提供的帮助。谢谢你的帮助。 B

A
DbSet
不是
DbSet
仅仅因为
MlaPerson
源自
WebObject
。搜索堆栈溢出上的“通用差异”以查找原因

您可能希望更改方法参数和约束,如下所示:

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);

我还建议您将类型参数重命名为类似于
TSource
TTarget
的名称,以便更清晰,并遵循约定。

您正在犯一个常见的泛型错误-假设集合是协变的。也就是说,
List
的实例不会从
List
继承,即使car从vehicle继承。同样地,
DbSet
不会继承自
DbSet
,即使MlaPerson继承自WebObject

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

受保护的void AddRelatedWebObject(一个MLAOObject、一个inputObject、一个列表GUID)
其中A:WebObject
其中B:DbSet
其中O:WebObject
{
foreach(Guid中的Guid)
{
添加(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);
}
foreach(ArticleRelationships中的ArticleRelationships项)
{
MlaArticle article=新的MlaArticle();
article=_db.MlaArticles.Include(m=>m.WebSite).Where(m=>m.Id==item.ArticleId).First();
AddRelatedWebObject(article,_db.mlaperson,item.PersonIds);
}
如果这样做,您可能会放弃类型规范(
),因为它应该推断出它。

--EDIT-这个答案是错误的。有关更多信息,请参阅评论--

向上转换不适用于容器(除非您向上转换数据结构,但这里不是这种情况)。设想以下代码(为了简单起见,使用数组编写,但相同的原则适用于所有通用容器):


现在
arrayB[0]
包含类型为A的对象,即使它
A
不是
B
的派生类。这就是为什么向上浇铸对容器不起作用。

这个答案是错误的;给定的代码在编译时成功。如果两种元素类型都是引用类型,则C#支持数组上的非类型安全元素类型差异。这是我的“C#最差特性”候选。这一行不会产生编译错误,如果你运行代码,你会发现它在运行时失败。。。这就是我在不检查代码的情况下根据知识回答问题的结果。。。无论如何,它不适用于通用容器(我确实检查过),但这可能是由于技术原因,而不是由于正确的语言设计。请有人否决我的答案。是的,没有什么比被一个负责C#work的家伙打得更惨的了:公司理性的人有理由认为这会在静态类型语言中产生编译错误;令人深感遗憾的是,它没有这样做。请注意,当编译器可以证明转换是类型安全的时,C#4确实支持使用引用类型参数构造的泛型接口和委托的协方差。@BahriGungor:遗憾的是,没有。
observateCollection
不是泛型接口或委托。相比之下,
IEnumerable
是一个通用接口,编译器可以证明协变地使用它是类型安全的。有关详细信息,请参阅常见问题解答:。如果您对该功能的设计感兴趣,请参阅我的关于如何设计它的系列文章。这看起来也对,我只是先尝试了另一个答案。不过我还是喜欢你。谢谢你的回答/解释。它是彻底且容易理解的。@bflemi3:我的答案比公认的答案(IMO)的好处在于它涉及的类型参数更少,因此更简单。我看不出
B
type参数实际上在做任何有用的事情。
public class MlaPerson : WebObject, IValidatableObject
{
    ...
}
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);
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);
}
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();