2009-07-29 116 views
41

我有一個類,其構造函數被定義爲internal,這意味着我無法實例化它。雖然這可能是有道理的,但我仍然希望爲了調試和研究目的而做一次。使用內部構造函數實例化一個類

用反射可以這麼做嗎?我知道我可以訪問私人/內部成員,但我可以調用內部構造函數嗎?或者,由於構造函數沒有什麼重要,我可以使用反射來說:「看,只給我一個類的實例,而不調用構造函數,我會做手動工作」?

性能和「穩定性」在這裏不是問題,因爲它不是生產代碼。

編輯:正如澄清:可悲的是,我沒有控制其他組件與沒有它的源代碼,我只是嘗試去了解它是如何工作的,因爲它的文檔旁邊不存在的,但我應該與它接口。

回答

28

A FormatterServices.GetUninitializedObject方法存在(命名空間:System.Runtime.Serialization),它應該不會調用構造函數,如果您確實想要嘗試這種方法。

+3

這和Type.GetField()/ FieldInfo.SetValue解決了我的問題。 – 2009-07-29 12:16:18

72

另一種方法是提名調用程序集爲「朋友」程序集。

只需將其添加到包含內部構造組裝的AssemblyInfo.cs文件:

[assembly: InternalsVisibleTo("Calling.Assembly")] 

如果您沒有訪問到組件,您也可以直接調用構造函數(使用反射):

MyClass obj = (MyClass) typeof(MyClass).GetConstructor(
        BindingFlags.NonPublic | BindingFlags.Instance, 
        null, Type.EmptyTypes, null).Invoke(null); 
+0

可悲的是我無法控制的其他組件:( – 2009-07-29 11:38:09

+1

編輯我的答案,包括使用反射 – 2009-07-29 11:44:16

+0

出於某種原因的解決方案,GetContructor返回null,隨着試驗的BindingFlags即使,但是一般它是一個有用的答案,所以+1 +1 – 2009-07-29 12:17:10

0

internal並不意味着你不能實例化它。這隻意味着只有來自同一會員的成員可能會這樣稱呼它。

出於測試目的,您可以允許測試程序集使用InternalsVisibleTo屬性訪問內部元素。請參閱http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx

+0

呃..如果你想從另一個程序集中實例化它,那麼你不能...... – cjk 2009-07-29 11:38:44

+0

正確的,除非你可以使用InternalsVisibleTo。隨着問題的更新不似乎是這種情況,但從原來的措辭我不明白。 – 2009-07-29 12:25:22

0

您可以使用Reflector來分析它的源代碼,並從中找出內部工作原理。

3

我經歷了同樣的情況,並創建了一個叫做「InternalsVisibleToInjector」的小工具。它使用ILDASM和ILASM來反彙編,修改和重組,並將我選擇的程序集名稱添加到目標程序集的InternalsVisibleTo列表中。在我的情況下它工作得很好。

我已經發布的源代碼(VS 2008 C#WinForm的),這裏的效用:

http://www.schematrix.com/downloads/InternalsVisibleToInjector.zip

如果大會簽署,這可能無法正常工作。請採取一切適當的預防措施(即在使用前備份裝配並確保您的法律基礎牢固等)。)

13

這是從this answer衍生的方法:

public static T CreateInstance<T>(params object[] args) 
{ 
    var type = typeof (T); 
    var instance = type.Assembly.CreateInstance(
     type.FullName, false, 
     BindingFlags.Instance | BindingFlags.NonPublic, 
     null, args, null, null); 
    return (T) instance; 
} 

實施例使用(這是我需要創建用於單元測試的Kinect SDK型):

DiscreteGestureResult a = CreateInstance<DiscreteGestureResult>(false, false, 0.5f); 
1

如果任何人絆倒再次介紹如何通過反射來提高它:

var args = FormatterServices.GetUninitializedObject(typeof(SizeChangedEventArgs)) as SizeChangedEventArgs; 
Debug.Assert(args != null); 

var field = typeof(SizeChangedEventArgs).GetField("_previousSize", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, new Size(0,0)); 
field = typeof(SizeChangedEventArgs).GetField("_element", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, GraphicsWrapper); 
field = typeof(RoutedEventArgs).GetField("_source", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, GraphicsWrapper); 
field = typeof(RoutedEventArgs).GetField("_routedEvent", BindingFlags.Instance | BindingFlags.NonPublic); 
Debug.Assert(field != null); 
field.SetValue(args, SizeChangedEvent); 

GraphicsWrapper.RaiseEvent(args); 

...其中th e GraphicsWrapper是您希望從中提出的WPF控件。

1

如果你想避免反射,你可以使用表達式。 這是一個使用字符串值調用私有構造函數的示例。

private static Func<string, T> CreateInstanceFunc() 
    { 
     var flags = BindingFlags.NonPublic | BindingFlags.Instance; 
     var ctor = typeof(T).GetConstructors(flags).Single(
      ctors => 
      { 
       var parameters = ctors.GetParameters(); 
       return parameters.Length == 1 && parameters[0].ParameterType == typeof(string); 
      }); 
     var value = Expression.Parameter(typeof(string), "value"); 
     var body = Expression.New(ctor, value); 
     var lambda = Expression.Lambda<Func<string, T>>(body, value); 

     return lambda.Compile(); 
    } 
相關問題