C# 使用内部构造函数实例化类

C# 使用内部构造函数实例化类,c#,.net,reflection,C#,.net,Reflection,我有一个类,它的构造函数被定义为internal,这意味着我不能实例化它。虽然这可能是有道理的,但出于调试和研究目的,我还是想做一次 有可能通过反射来实现吗?我知道我可以访问私有/内部成员,但我可以调用内部构造函数吗 或者,由于构造函数不做任何重要的事情,我可以使用反射说“看,只给我一个类的实例而不调用构造函数,我将手动完成它的工作”吗 性能和“稳定性”在这里不是问题,因为它不是生产代码 编辑:正如澄清:遗憾的是,我不控制另一个程序集,也没有它的源代码,我只是试图理解它是如何工作的,因为它的文档

我有一个类,它的构造函数被定义为internal,这意味着我不能实例化它。虽然这可能是有道理的,但出于调试和研究目的,我还是想做一次

有可能通过反射来实现吗?我知道我可以访问私有/内部成员,但我可以调用内部构造函数吗

或者,由于构造函数不做任何重要的事情,我可以使用反射说“看,只给我一个类的实例而不调用构造函数,我将手动完成它的工作”吗

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


编辑:正如澄清:遗憾的是,我不控制另一个程序集,也没有它的源代码,我只是试图理解它是如何工作的,因为它的文档几乎不存在,但我应该与它交互。

另一种选择是将调用程序集指定为“朋友”程序集

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

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

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


internal
并不意味着不能实例化它。这只意味着只有来自同一个大会的成员才可以召集会议


出于测试目的,您可以使用InternalsVisibleTo属性允许测试程序集访问内部构件。请参见

存在一个方法(名称空间:System.Runtime.Serialization),如果您真的想尝试这种方法,它应该不会调用构造函数。

您可以使用它来分析其源代码并从中找出内部工作原理。

我不久前也遇到过同样的情况,并创建了一个我调用的小实用程序“InternalsVisibleToInjector”。它使用ILDASM和ILASM进行拆解、修改和重新组装,并将我选择的程序集名称添加到目标程序集的InternalsVisibleTo列表中。在我的情况下,它运行得相当好

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


如果程序集已签名,则此方法可能无效。请采取所有适当的预防措施(即在使用此方法之前备份程序集,并确保您有可靠的法律依据等)

此方法源自:

公共静态T CreateInstance(参数对象[]args) { var类型=类型(T); var instance=type.Assembly.CreateInstance( type.FullName,false, BindingFlags.Instance | BindingFlags.NonPublic, null,args,null,null); 返回(T)实例; } 用法示例(这是我为单元测试创建的Kinect SDK类型):

DiscreteTestureResult a=CreateInstance(false,false,0.5f);

如果有人再次无意中发现这一点,下面是一个如何通过反射提高它的示例:

MyClass obj = (MyClass) typeof(MyClass).GetConstructor(
                  BindingFlags.NonPublic | BindingFlags.Instance,
                  null, Type.EmptyTypes, null).Invoke(null);
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控件。

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

    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();
    }
private static Func CreateInstanceFunc()
{
var flags=BindingFlags.NonPublic | BindingFlags.Instance;
var ctor=typeof(T).getconstructor(flags).Single(
系数=>
{
var parameters=ctors.GetParameters();
返回参数。长度==1&¶meters[0]。参数类型==typeof(字符串);
});
var value=表达式参数(typeof(string),“value”);
var body=表达式.New(向量,值);
var lambda=表达式.lambda(主体,值);
返回lambda.Compile();
}

下面是一个更实际的示例。我想从实体框架实例化一个
对象物化EventTarget
。它如下所示:

namespace System.Data.Entity.Core.Objects
{
    /// <summary>EventArgs for the ObjectMaterialized event.</summary>
    public class ObjectMaterializedEventArgs : EventArgs
    {
        private readonly object _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; }
        }
    }
}
我在这里使用
GetConstructors
,指定要查找的构造函数是非公共的(例如内部构造函数),实例为
bindingflags
,然后使用
FirsOrDefault


希望此场景对那些在获取
GetConstructor
正确性方面有困难的人有所帮助。您可以使用
GetConstructors
,并在必要时过滤更多。然后在
?.Invoke()
中传递参数的对象数组。

很遗憾,我无法控制其他程序集:(编辑了我的答案以包含使用Reflection的解决方案出于某种原因,GetConstructor返回null,即使在尝试BindingFlags时也是如此。但通常这是一个有用的答案,因此+1。呃..如果您想从另一个程序集实例化它怎么办。那么您无法..更正,除非您可以在更新时使用InternalsVisibleTo这个问题似乎不是这样,但从最初的措辞来看,我并不清楚/FieldInfo.SetValue解决了我的问题。@Kenan:如果构造函数接受参数并对这些参数进行操作,那么最好使用反射并调用它,而不是创建一个统一化的对象并从“外部”实例复制构造函数行为“使用反射。在我看来,Tore解决方案更好。@AdamPlocher-lol你自己。OP清楚地指出,“我只是试图理解它是如何工作的。”。对IL中的代码进行反向工程,imho,是理解代码的一种非常可行的方法。我想说,为了理解某些程序集的内部工作,阅读代码比试图在运行时插入实例更容易。因此,我的答案是正确的,不管是否被否决。@AdamPlocher:我5年前的答案和其他答案一样古老这个问题的答案。嘿,即使这个问题已经5年了!那是怎么回事?B/c…不可能调用内部ctor。因此上面的例子。在接受的答案中使用FormatterServices.GetUninitializedObject()方法,你就绕过了这个限制。对不起,我没有付钱
    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();
    }
namespace System.Data.Entity.Core.Objects
{
    /// <summary>EventArgs for the ObjectMaterialized event.</summary>
    public class ObjectMaterializedEventArgs : EventArgs
    {
        private readonly object _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; }
        }
    }
}
[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);
}