簡體   English   中英

通用接口屬性在實現中是虛擬的

[英]Generic interface property is virtual in implementation

我有一個名為“ Entity”的模型,該模型實現了“ IEntity”接口,如下所示(簡化):

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

我想克隆此“實體”模型的對象,同時忽略以下虛擬屬性:

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

在這里,問題在於LayoutId的訪問器不是虛擬的,而Id的訪問器是虛擬的! 請同時查看兩個QuickWatch窗口: ID的訪問者是虛擬的LayoutId的訪問器不是虛擬的

為什么會發生這種情況? 這是因為Id是通用接口“ IEntity”的實現屬性嗎? 如果是這樣,並且這是預期的行為,為什么?

謝謝,

功力

簡短的版本是這就是CLR的工作方式。 請注意MethodBase文檔中的這段文字:

公共語言運行時要求所有實現接口成員的方法都必須標記為虛擬

換句話說:之所以這樣,是因為CLR表示必須采用這種方式。

更一般而言,當在編譯時不知道要分派的方法時,將使用虛擬方法。 對於未聲明為virtual方法且未實現某些接口成員的方法,C#編譯器可以在編譯時確定要調用的方法,並可以在IL中生成特定的,效率更高的方法調用類型,以用於這個目的。

對於其他方法,可能需要從實際實現類型未知的上下文中調用它們,因此必須通過方法表( “ vtable” )路由對此類方法的調用。 這既適用於實際的virtual方法(即,這樣聲明的方法),也適用於實現接口成員的方法,因為可以從(通常是)從上下文中調用后一種方法,在該上下文中,所有已知的只是接口類型,而不是實際的實現類型。 通過使用vtable,調用者只需知道vtable的位置和格式,而不是實現類型即可。

因為真正的virtual方法和接口成員的功能基本相同,所以在底層CLR實現級別上,它們都被視為相同。 (通常…在文檔中也要注意,接口實現成員也被標記為final ,指示它們不能被覆蓋)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM