2014-10-17 87 views
0

我試圖通過反射創建一個DbEntityEntry<T>用於測試目的。它的構造是內部的,但我想調用它,並通過在實體:實例化DbEntityEntry <T>與反射

public DbEntityEntry<T> Entry<T>(T entity) where T : class 
    { 
     Type constructedType = typeof(DbEntityEntry<T>); 
     BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
     object x = Activator.CreateInstance(constructedType, flags, null, new object[] { entity }, null); 

我得到:上式「System.Data.Entity.Infrastructure.DbEntityEntry`1 [

構造[System.Object,mscorlib,Version = 4.0.0.0,Culture = neutral,PublicKeyToken = b77a5c561934e089]]'找不到。

源的構造函數是:

internal DbEntityEntry(InternalEntityEntry internalEntityEntry) 
    { 
     DebugCheck.NotNull(internalEntityEntry); 

     _internalEntityEntry = internalEntityEntry; 
    } 

任何方式創建一個實例?

UPDATE:

原代碼實際上是由馬克Gravell以前的答案之一解除,但由於這個職位的候選接近,我將提供另一種嘗試使用Gravell的答案的建議:

Type[] argTypes = new Type[] { typeof(T) }; 
object[] argValues = new object[] { entity }; 
BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Instance; 
ConstructorInfo ctor = typeof (DbEntityEntry<T>).GetConstructor(flags, null, CallingConventions.Any, argTypes, null); 
object obj = ctor.Invoke(argValues); 

ctor爲空,所以再次找不到構造函數。

回答

0

而是詢問如何實例化一個第三方類型與反思的問如何改變你的代碼,以便它是可測試的,不需要黑客。如果你看看你發佈的DbEntityEntry ctor,你會發現它需要一個InternalEntityEntry對象 - 你將不得不實例化的另一個內部類(帶反射)。所以即使你沒有深入瞭解它們應該如何真正一起工作,並且如果EF碰巧以不同的方式創建這些對象,你最終也會自己創建大量內部對象,因此測試可能無用,因爲它們仍然可以通過該方案將無法正常工作。此外,因爲它是內部的東西,它可以在下一個版本中更改,並且您的測試可能無法正確使用新版本。您的帖子中沒有足夠的詳細信息能夠提供更好的建議。請注意,您可以使用公共API和DbContext.Entry()方法創建DbEntityEntry

+0

我確實認爲這是正確的途徑。 – 2014-10-17 16:49:48

+0

如果您不滿意答案,請解釋原因。 – Pawel 2016-03-01 16:34:24

+0

我正在爲DbEntityValidationException的擴展方法編寫一個測試。爲了測試它,我需要創建一個DbEntityValidationResult的實例,但這需要一個DbEntityEntry的實例,並且在那裏我發現了這個問題。我同意你關於改變代碼,但在我的情況下,我不明白我該怎麼做。有任何想法嗎? – 2017-01-24 21:58:26

1

試着用這個。

public DbEntityEntry<T> Entry<T>(T entity) 
    where T : class 
{ 
    ConstructorInfo constructor = null; 

    try 
    { 
     // Binding flags exclude public constructors. 
     constructor = typeof(DbEntityEntry<T>) 
      .GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, 
      new Type[] { typeof(InternalEntityEntry) }, null); 
    } 
    catch (Exception exception) 
    { 
     throw new Exception("Error Finding Constructor", exception); 
    } 

    if (constructor == null) // || constructor.IsAssembly) 
     // Also exclude internal constructors ... note, were including for this example 
     throw new Exception(string.Format("A private or " + 
       "protected constructor is missing for '{0}'.", typeof(DbEntityEntry<T>).Name)); 

    return (DbEntityEntry<T>)constructor.Invoke(new object[] { entity }); 
} 
+0

看起來非常好,除了'InternalEntityEntry'是EF組件的'internal' ...任何想法如何解決這個問題? – 2014-10-17 16:21:31

+0

可能Type.GetType(「System.Data.Entity.Internal.InternalEntityEntry」),但你必須仔細檢查 - 我不認爲我有正確的EF加載tho ...我會看看如果我可以得到EF 5加載。 – 2014-10-17 16:25:57

+0

謝謝特拉維斯,但我們可以通過這種方式檢索內部類型嗎? – 2014-10-17 16:31:50