C# 实例化DbEntityEntry<;T>;深思熟虑

C# 实例化DbEntityEntry<;T>;深思熟虑,c#,entity-framework,C#,Entity Framework,我正试图通过反射创建一个DbEntityEntry,用于测试目的。它的构造函数是内部的,但我想调用它并传入一个实体: public DbEntityEntry<T> Entry<T>(T entity) where T : class { Type constructedType = typeof(DbEntityEntry<T>); BindingFlags flags = BindingFlags.NonPublic

我正试图通过反射创建一个
DbEntityEntry
,用于测试目的。它的构造函数是内部的,但我想调用它并传入一个实体:

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);
有没有办法创建一个实例

更新:

原来的代码实际上是从Marc 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);
Type[]argTypes=新类型[]{typeof(T)};
对象[]argValues=新对象[]{entity};
BindingFlags=BindingFlags.NonPublic | BindingFlags.Instance;
ConstructorInfo-ctor=typeof(DbEntityEntry).GetConstructor(标志,null,调用约定.Any,argTypes,null);
object obj=ctor.Invoke(argValues);
ctor
为空,因此无法再次找到构造函数。

尝试使用此方法

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 });
}
公共数据库实体条目(T实体)
T:在哪里上课
{
ConstructorInfo constructor=null;
尝试
{
//绑定标志不包括公共构造函数。
构造函数=类型(DbEntityEntry)
.GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic,null,
新类型[]{typeof(InternalEntityEntry)},null;
}
捕获(异常)
{
抛出新异常(“错误查找构造函数”,异常);
}
if(constructor==null)/| | constructor.IsAssembly)
//还排除了内部构造函数…注意,本例中包括了
抛出新异常(string.Format(“私有或”+
“{0}”缺少受保护的构造函数,typeof(DbEntityEntry.Name));
return(DbEntityEntry)构造函数。Invoke(新对象[]{entity});
}

不要询问如何使用反射实例化第三方类型,而要询问如何更改代码,使其可测试且不需要黑客攻击。如果查看您发布的
DbEntityEntry
ctor,您将看到它需要一个
InternalEntityEntry
对象—另一个必须实例化(带有反射)的内部类。因此,即使您不知道内部对象应该如何真正协同工作,您也会自己创建大量内部对象,如果EF碰巧以不同的方式创建这些对象,那么您的测试可能是无用的,因为即使程序无法工作,它们仍然可以通过。此外,因为它是内部的东西,它可以在下一个版本中更改,并且您的测试可能无法在新版本中正常工作。您的帖子中没有足够的细节,无法提供更好的建议。请注意,您可以使用此方法使用公共API创建
DbEntityEntry

看起来非常好,除了
InternalEntityEntry
是EF程序集的
internal
。。。你知道如何解决这个问题吗?可能键入.GetType(“System.Data.Entity.Internal.InternalEntityEntry”),但你必须仔细检查-我想我没有正确的EF加载到这些。。。我看看能不能装上EF 5。谢谢特拉维斯,但我们能用这种方法找回一个内部类型吗?经过进一步的调查,我相信帕维尔的推理是正确的。。。InternalEntityEntry本身使用另一种类型的InternalContext。在继续之前,您可能需要检查您的方法和。另外,从长远来看,使用他描述的OOB方法可能会更好。我相信这是正确的方法。我正在为DbEntityValidationException的扩展方法编写测试。为了测试它,我需要创建一个DbEntityValidationResult实例,但这需要一个DbEntityEntry实例,这就是我发现这个问题的地方。我同意你关于修改代码的看法,但在我的场景中,我不知道我如何才能做到这一点。有什么想法吗?也许写一个端到端测试?
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 });
}