c#-使用内部构造实例化类

我有一个其构造函数定义为内部的类,这意味着我无法实例化它。 尽管这可能很有意义,但我仍然想为调试和研究目的这样做一次。

反射可以做到吗? 我知道我可以访问私有/内部成员,但是我可以调用内部构造函数吗?

或者,由于构造函数没有什么重要的事情,我可以使用反射来表示“看,只要给我一个类的实例,而无需调用构造函数,我将手动完成它”?

性能和“稳定性”在这里不是问题,因为它不是生产代码。

编辑:澄清一下:可悲的是,我不控制另一个程序集,也没有它的源代码,我只是试图了解它的工作原理,因为它的文档几乎不存在,但是我应该与 它。

Michael Stum asked 2020-02-21T06:33:00Z
9个解决方案
85 votes

一种替代方法是将调用程序集提名为“朋友”程序集。

只需将其添加到包含内部构造函数的程序集的AssemblyInfo.cs文件中:

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

如果您无权访问程序集,则还可以直接调用构造函数(使用Reflection):

MyClass obj = (MyClass) typeof(MyClass).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, Type.EmptyTypes, null).Invoke(null);
Philippe Leybaert answered 2020-02-21T06:39:18Z
31 votes

存在FormatterServices.GetUninitializedObject方法(名称空间:System.Runtime.Serialization),如果您真的想尝试该方法,则据说不调用任何构造函数。

Kenan E. K. answered 2020-02-21T06:38:49Z
20 votes

这是从此答案派生的方法:

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);
weston answered 2020-02-21T06:39:43Z
3 votes

不久前,我遇到了同样的情况,并创建了一个名为“ InternalsVisibleToInjector”的小实用程序。 它使用ILDASM和ILASM进行反汇编,修改以及重新组装和装配,并将我选择的装配名称添加到目标装配的InternalsVisibleTo列表中。 在我的情况下,它工作得很好。

我已经在此处发布了该实用程序的源代码(VS 2008 C#WinForm):

[HTTP://呜呜呜.S车matrix.com/downloads/internal是visible to injector.zip]

如果程序集已签名,这可能不起作用。 请采取所有适当的预防措施(即,在使用前对程序集进行备份,并确保您拥有可靠的法律依据等)。

Michael A. McCloskey answered 2020-02-21T06:40:18Z
2 votes

如果要避免反射,可以使用表达式。这是一个使用字符串值调用私有构造函数的示例。

    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();
    }
Xavier John answered 2020-02-21T06:40:40Z
1 votes

如果有人再次偶然发现此问题,下面是一个如何通过反射将其升高的示例:

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

...其中GraphicsWrapper是您要引发它的WPF控件。

outbred answered 2020-02-21T06:41:05Z
1 votes

这是一个更实际的例子。 我想从实体框架实例化ObjectMaterializedEventArg。 看起来像这样:

namespace System.Data.Entity.Core.Objects

{   /// ObjectArgerialized事件的EventArgs。   公共类ObjectMaterializedEventArgs:EventArgs   {     私有只读对象_entity;

internal ObjectMaterializedEventArgs(object entity)
{
  this._entity = entity;
}

/// <summary>Gets the entity object that was created.</summary>
/// <returns>The entity object that was created.</returns>
public object Entity
{
  get
  {
    return this._entity;
  }
}

}}

如我们所见,此事件arg仅具有内部构造函数。

为了对使用的软件系统中的患者解密规则进行单元测试,我们需要实例化此类对象,因此最终我改用GetConstructors方法。

    [Test]
    public void EmptyNameAndOfficialIdDoesNotThrow()
    {
        var patientDecryptingRule = new PatientDecryptingRule();
        object[] reservation = new object[]
        {
            new Operation
            {
                Status = (int) OperationStatusDataContract.Reservation,
                Patient = new Patient
                {
                    Name = null,
                    OfficialId = null,
                    IsPatientEncrypted = true
                }
            }
        };
        var relevantConstructor = typeof(ObjectMaterializedEventArgs).GetConstructors(
            BindingFlags.NonPublic | BindingFlags.Instance).FirstOrDefault();
        ObjectMaterializedEventArgs objectMaterializedEventArgs =
            (ObjectMaterializedEventArgs) relevantConstructor?.Invoke(reservation);
        patientDecryptingRule.ModifyObjectMaterialized(objectMaterializedEventArgs);
    }

我在这里使用GetConstructors,指定要查找的构造函数是非公共的(例如内部),并且实例作为绑定标志,然后使用FirsOrDefault。

希望这种情况对某些无法正确获取GetConstructor的人有所帮助。 您可以改用GetConstructors并根据需要过滤更多内容。 然后在?.Invoke中传递参数的对象数组。

Tore Aurstad answered 2020-02-21T06:45:30Z
0 votes

internal并不意味着您无法实例化它。 这只是意味着只有来自同一程序集的成员才能调用它。

出于测试目的,您可以允许您的测试程序集也使用InternalsVisibleTo属性访问内部。 请参阅[http://msdn.microsoft.com/zh-cn/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx]

Brian Rasmussen answered 2020-02-21T06:45:56Z
0 votes

您可以使用Reflector来分析其源代码,然后从中找出其内部工作原理。

Peter Lillevold answered 2020-02-21T06:46:16Z
translate from https://stackoverflow.com:/questions/1199590/instancing-a-class-with-an-internal-constructor