简体   繁体   中英

Generic interface property is virtual in implementation

I have a model called 'Entity' which implements 'IEntity' interface as follows (simplified):

public interface IEntity<T> where T : IComparable
{
    T Id { get; set; }
}

public class Entity: IEntity<Guid>
{
    public Guid Id { get; set; }
    public Guid LayoutId { get; set; }
    public virtual Layout Layout {get; set;}
}

I would like to clone an object of this 'Entity' model while ignoring virtual properties as follows:

public static class CloneHelper
{
    public static T CloneNonVirtual<T>(this T source) where T : class
    {
        var cloneObj = Activator.CreateInstance<T>();
        foreach (var prop in source.GetType().GetProperties().Where(w => w.CanWrite && !w.GetAccessors().Any(x => x.IsVirtual)))
        {
            var cloneObjProp = cloneObj.GetType().GetProperty(prop.Name);
            cloneObjProp.SetValue(cloneObj, prop.GetValue(source));
        }
        return cloneObj;
    }
}

Here, the problem is that LayoutId's accessors are not virtual, but Id's accessors are! Please see both QuickWatch windows: ID的访问者是虚拟的LayoutId的访问器不是虚拟的

Why does this occur? Is this because Id is an implemented property of the generic interface 'IEntity'? If so and if this is intended behavior, why?

Thanks,

Ferit

The short version is that this is just how the CLR works. Note this text from the documentation for MethodBase :

The common language runtime requires that all methods that implement interface members must be marked as virtual

In other words: it's that way because the CLR says it has to be that way.

More generally, virtual methods are used when the method to be dispatched is not known at compile-time. For methods which are not declared virtual and which don't implement some interface member, the C# compiler can determine at compile-time what method is to be called, and can generate a specific, slightly more efficient type of method call in the IL for that purpose.

For other methods, where they may need to be called from a context where the actual implementing type is unknown, calls to such methods have to be routed through a table of methods ( "vtable" ). This applies both to actual virtual methods (ie those declared as such), and to methods implementing interface members, since those latter methods could be (and often are) called from a context where all that's known is the interface type and not the actual implementing type. Through the use of the vtable, all the caller needs to know is the location and format of the vtable, rather than the implementing type.

Because the functionality for true virtual methods and interface members is basically the same, at the underlying CLR implementation level, they are both treated the same. (Mostly…note also in the documentation that interface implementation members are also marked final , indicating that they can't be overridden).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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