阻止此类之外的类的实例化

本文关键字:实例化 | 更新日期: 2023-09-27 18:25:15

我使用Entity Framework和为DbContext生成的类。这些类是生成的,我所做的每一次更改都会在下次刷新DbContext时被覆盖。

现在我重写这个类来动态生成到数据库的连接,这很好。但问题是,您也可以使用无参数构造函数创建类,如果连接不是动态的,这会导致大问题
是否有任何方法可以禁止在生成类之外使用无参数构造函数实例化生成类?

例如:
生成的没有参数的类:

public partial class SomeConnection : DbContext
{
    public SomeConnection()
        : base("name=myWrongConnection")
    {
       //should not be able to be called!
    }
    // some more generated and needed stuff!
    ...
}

这里是我需要实例化的类:

public partial class SomeConnection
{
    public SomeConnection(String connectionString)
        : base(connectionString)
    {
        // only this constructor should be called without changing the parent class...
    }
}

阻止此类之外的类的实例化

最好使用工厂,但如果您绝对需要禁止使用错误的实例,一个可能的解决方法是重写OnModelCreating,因此即使使用错误的构造函数创建实例也无法使用:

public partial class SomeConnection
{
  private readonly bool correctConstructorWasCalled;
  public DerivedContext(string connectionString)
            :base(connectionString)
  {
      correctConstructorWasCalled = true;
  }
  protected override void OnModelCreating(DbModelBuilder modelBuilder)
  {
    if (!correctConstructorWasCalled)
    {
        throw new InvalidOperationException("Please call the correct constructor.");
    }
    base.OnModelCreating(modelBuilder);
  }
}

更新:

我找到了一个绝对拒绝特定构造函数的解决方案:

public class Guard
{
  public Guard([CallerMemberName] string callerName = null)
  {
    var constructorExpression = (Expression<Func<Prohibited>>)(() => new Prohibited());
    var constructorMethod = (NewExpression) (constructorExpression.Body);
    var stackFrames = new StackTrace().GetFrames();
    if (stackFrames.Any(f => f.GetMethod() == constructorMethod.Constructor))
    {
      throw new InvalidOperationException("Aha! you are still trying.");
    }
  }
}
public partial class Prohibited : DbContext
{
   public Prohibited()
            : base("wrong connection string")
   {
   }
}
public partial class Prohibited 
{
  private Guard guard = new Guard();
  public Prohibited(string connectionString)
            : base(connectionString)
  {
  }
}

需要[CallerMemberName],因此在Release配置中不会优化调用方帧。