简体   繁体   English

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

[英]c# Type Inference - Error - There is no implicit reference conversion from

I have a method that loops through a list of guids and saves them to a database via DbContext. 我有一个循环guid列表的方法,并通过DbContext将它们保存到数据库。 B is a DbSet collection of WebObjects (example: DbSet<MlaPerson> MlaPersons ) 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();
    }
}

usage : 用法

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.MlaPersons are defined as : _db.MlaPersons定义为

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

and MlaPerson is defined as : 和MlaPerson定义为

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

I thought that by inferring that B was DbSet<WebObject> would work because MlaPerson's base class is WebObject, but I'm wrong. 我认为通过推断B是DbSet<WebObject>会起作用,因为MlaPerson的基类是WebObject,但我错了。 I'm getting the error: 我收到错误:

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>'

I would really appreciate any and all help offered. 我非常感谢所提供的任何和所有帮助。 Thanks for your help. 谢谢你的帮助。 B

You are making a common generics error- assuming that collections are covariant. 您正在制作一个常见的泛型错误 - 假设集合是协变的。 That is, a an instance of List<Car> does not inherit from List<Vehicle> even though car inherits from vehicle. 也就是说,即使汽车继承车辆, List<Car>的实例也不会从List<Vehicle>继承。 Likewise, DbSet<MlaPerson> does not inherit from DbSet<WebObject> even though MlaPerson inherits from WebObject. 同样,即使MlaPerson继承自WebObject, DbSet<MlaPerson>也不会从DbSet<WebObject>继承。

What you need to do is something like this (I haven't tested this code): 你需要做的是这样的事情(我还没有测试过这段代码):

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

and use it thus: 并使用它:

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

If you do it this way, you may be able to forgo the type specification ( <MlaArticle, DbSet<MlaPerson>, MlaPerson> ) because it should infer it. 如果你这样做,你可能会放弃类型规范( <MlaArticle, DbSet<MlaPerson>, MlaPerson> ),因为它应该推断它。

A DbSet<MlaPerson> isn't a DbSet<WebObject> just because MlaPerson derives from WebObject . DbSet<MlaPerson>不是DbSet<WebObject> ,因为MlaPerson派生自WebObject Search for "generic variance" on Stack Overflow to find lots of reasons why. 在Stack Overflow上搜索“generic variance”以查找原因。

You might want to change your method parameters and constraints like this: 您可能希望更改方法参数和约束,如下所示:

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

And then call it like this: 然后像这样调用它:

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

That may work - it may even work with type inference to allow this: 这可能有效 - 它甚至可以使用类型推断来实现:

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

I would also suggest that you rename your type parameters to something like TSource and TTarget to be clearer, and to follow conventions. 建议您将类型参数重命名为TSourceTTarget ,以便更清楚,并遵循惯例。

--EDIT - THIS ANSWER IS WRONG. --EDIT - 这个答案是错的。 SEE THE COMMENTS FOR MORE INFO-- 看到更多信息的评论 -

Upcasting does not work with containers(unless you are upcasting the data structure, but that's not the case here). 向上转换不适用于容器(除非您正在向上转换数据结构,但这不是这种情况)。 Imagine the following code(written with arrays for simplicity, but the same principles apply for all generic containers): 想象一下下面的代码(为简单起见用数组编写,但同样的原则适用于所有通用容器):

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

Now arrayB[0] contains an object of type A, even though it A is not a derived class of B . 现在arrayB[0]包含类型A的对象,即使它A不是派生的类的B That's why upcasting does not work for containers. 这就是为什么向上转换不适用于容器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM