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:
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.