在以下博客:http://weblogs.asp.net/scottgu/archive/2010/07/16/code-first-development-with-entity-framework-4.aspx

该博客包含以下代码示例:

public class Dinner
{
   public int DinnerID { get; set; }
   public string Title { get; set; }
   public DateTime EventDate { get; set; }
   public string Address { get; set; }
   public string HostedBy { get; set; }
   public virtual ICollection<RSVP> RSVPs { get; set; }
}

public class RSVP
{
   public int RsvpID { get; set; }
   public int DinnerID { get; set; }
   public string AttendeeEmail { get; set; }
   public virtual Dinner Dinner { get; set; }
}

在类中定义属性时使用virtual的目的是什么?它有什么影响?


当前回答

我理解OPs的挫败感,虚拟的这种使用并不是为了模板化抽象,而事实上的虚拟修饰符是有效的。

如果有人还在为这个问题而挣扎,我将提供我的观点,因为我试图保持解决方案的简单性,并将术语降至最低:

实体框架在一个简单的部分中确实利用了惰性加载,这相当于为将来的执行做准备。这符合“虚拟”修饰符,但还有更多。

在实体框架中,使用虚拟导航属性允许您将其表示为等同于SQL中的可空外键。在执行查询时,您不必急切地连接每个键表,但当您需要信息时——它就变成了需求驱动的。

I also mentioned nullable because many navigation properties are not relevant at first. i.e. In a customer / Orders scenario, you do not have to wait until the moment an order is processed to create a customer. You can, but if you had a multi-stage process to achieve this, you might find the need to persist the customer data for later completion or for deployment to future orders. If all nav properties were implemented, you'd have to establish every Foreign Key and relational field on the save. That really just sets the data back into memory, which defeats the role of persistence.

So while it may seem cryptic in the actual execution at run time, I have found the best rule of thumb to use would be: if you are outputting data (reading into a View Model or Serializable Model) and need values before references, do not use virtual; If your scope is collecting data that may be incomplete or a need to search and not require every search parameter completed for a search, the code will make good use of reference, similar to using nullable value properties int? long?. Also, abstracting your business logic from your data collection until the need to inject it has many performance benefits, similar to instantiating an object and starting it at null. Entity Framework uses a lot of reflection and dynamics, which can degrade performance, and the need to have a flexible model that can scale to demand is critical to managing performance.

对我来说,这总是比使用过多的技术术语(如代理、委托、处理程序等)更有意义。一旦你接触到第三或第四个编程语言,这些就会变得很混乱。

其他回答

谈论虚拟成员时不能不提到多态性。事实上,基类中标记为virtual的函数、属性、索引器或事件将允许从派生类重写。

默认情况下,类的成员是非虚的,并且不能被标记为静态、抽象、私有或覆盖修饰符。

例子 让我们考虑System.Object中的ToString()方法。因为这个方法是System的成员。对象,它在所有类中继承,并将为所有类提供ToString()方法。

namespace VirtualMembersArticle
{
    public class Company
    {
        public string Name { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Company company = new Company() { Name = "Microsoft" };
            Console.WriteLine($"{company.ToString()}");
            Console.ReadLine();
        }   
    }
}

上面代码的输出是:

VirtualMembersArticle.Company

假设我们想要改变从System继承的ToString()方法的标准行为。对象的Company类。要实现这个目标,使用override关键字声明该方法的另一个实现就足够了。

public class Company
{
    ...
    public override string ToString()
    {
        return $"Name: {this.Name}";
    }         
}

现在,当调用虚方法时,运行时将检查其派生类中的覆盖成员,如果存在则调用它。我们的应用程序的输出将是:

Name: Microsoft

事实上,如果你检查系统。对象类时,您会发现该方法被标记为virtual。

namespace System
{
    [NullableContextAttribute(2)]
    public class Object
    {
        ....
        public virtual string? ToString();
        ....
    }
}

在EF的上下文中,将属性标记为virtual允许EF使用延迟加载来加载它。为了使延迟加载工作,EF必须创建一个代理对象,该对象覆盖您的虚拟属性,并在首次访问时加载被引用实体的实现。如果您没有将属性标记为virtual,那么惰性加载将无法使用它。

It’s quite common to define navigational properties in a model to be virtual. When a navigation property is defined as virtual, it can take advantage of certain Entity Framework functionality. The most common one is lazy loading. Lazy loading is a nice feature of many ORMs because it allows you to dynamically access related data from a model. It will not unnecessarily fetch the related data until it is actually accessed, thus reducing the up-front querying of data from the database.

摘自《ASP。NET MVC 5与Bootstrap和Knockout.js

我理解OPs的挫败感,虚拟的这种使用并不是为了模板化抽象,而事实上的虚拟修饰符是有效的。

如果有人还在为这个问题而挣扎,我将提供我的观点,因为我试图保持解决方案的简单性,并将术语降至最低:

实体框架在一个简单的部分中确实利用了惰性加载,这相当于为将来的执行做准备。这符合“虚拟”修饰符,但还有更多。

在实体框架中,使用虚拟导航属性允许您将其表示为等同于SQL中的可空外键。在执行查询时,您不必急切地连接每个键表,但当您需要信息时——它就变成了需求驱动的。

I also mentioned nullable because many navigation properties are not relevant at first. i.e. In a customer / Orders scenario, you do not have to wait until the moment an order is processed to create a customer. You can, but if you had a multi-stage process to achieve this, you might find the need to persist the customer data for later completion or for deployment to future orders. If all nav properties were implemented, you'd have to establish every Foreign Key and relational field on the save. That really just sets the data back into memory, which defeats the role of persistence.

So while it may seem cryptic in the actual execution at run time, I have found the best rule of thumb to use would be: if you are outputting data (reading into a View Model or Serializable Model) and need values before references, do not use virtual; If your scope is collecting data that may be incomplete or a need to search and not require every search parameter completed for a search, the code will make good use of reference, similar to using nullable value properties int? long?. Also, abstracting your business logic from your data collection until the need to inject it has many performance benefits, similar to instantiating an object and starting it at null. Entity Framework uses a lot of reflection and dynamics, which can degrade performance, and the need to have a flexible model that can scale to demand is critical to managing performance.

对我来说,这总是比使用过多的技术术语(如代理、委托、处理程序等)更有意义。一旦你接触到第三或第四个编程语言,这些就会变得很混乱。

c#中的virtual关键字使方法或属性可以被子类覆盖。要了解更多信息,请参考MSDN文档中关于“virtual”关键字的文档

更新:这并没有回答目前提出的问题,但我将把它留在这里,供那些寻找原始的、非描述性问题的简单答案的人使用。