使用FormatterServices.GetUninitializedObject初始化的对象上的NullReferenceException

时间:2014-10-17 14:58:18

标签: c# entity-framework nullreferenceexception

我嘲笑DbContext,在我的测试中,我想确保实体被标记为删除。当我在模拟上下文中标记每个对象时,我使用静态字典跟踪每个实体:

public DbEntityEntry<T> Entry<T>(T entity) where T : class
{
    var entry = (DbEntityEntry<T>)FormatterServices.GetUninitializedObject(typeof(DbEntityEntry<T>));

    var state = entityStates[entity];
    entry.State = state;

    return entry;
}

public void SetEntityState(object entity, System.Data.EntityState state)
{
    entityStates.Add(entity, state);
    Entry(entity).State = state;
}

private static Dictionary<object, EntityState> entityStates = new Dictionary<object, EntityState>();

我无法通过DbEntityEntry实例化Activator.CreateInstance(),因此我已使用FormatterServices.GetUninitializedObject()进行实例化。

问题是这一行:

entry.State = state;

尝试分配给此属性会导致:

 NullReferenceException: Object reference not set to an instance of an object.

显然,在给定函数名称的情况下,对象不会被初始化,但我不确定为什么我可以在不抛出此异常的情况下分配对象的属性。

FWIW,测试看起来像:

 TripManager.DeleteTripsByForeignKey(int carId);

 var trip1 = _fakeDbContext.Trips.FirstOrDefault(t => t.TripId == 1);

 var entry = _fakeDbContext.Entry(trip1);

 Assert.AreEqual(EntityState.Deleted, entry.State);

1 个答案:

答案 0 :(得分:0)

FormatterServices.GetUninitializedObject不会调用该类型的任何构造函数。这意味着具有默认值或在构造函数中设置的字段不会被设置。如果您查看State属性的定义(https://github.com/mono/entityframework/blob/master/src/EntityFramework/Infrastructure/DbEntityEntry.cs - 请原谅单声道版本的链接),您可以看到setter依赖于_internalEntityEntry,它在构造函数中设置:

internal DbEntityEntry(InternalEntityEntry internalEntityEntry)
{
    _internalEntityEntry = internalEntityEntry;
}

这当然是为什么你不应该弄乱FormatterServices.GetUninitializedObject:)

如果你真的知道你在做什么,你可以明确地调用内部构造函数并嘲笑InternalEntityEntry ......但这似乎是一个非常糟糕的主意。