2009-07-29 140 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(); 
    } 
相关问题