- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - phát hiện rò rỉ bộ nhớ Ruby/Ruby on Rails
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
Unity 依赖项注入(inject)容器有一个似乎广为人知的问题,即 SynchronizedLifetimeManager 经常会导致 Monitor.Exit 方法抛出 SynchronizationLockException,该异常随后会被捕获并忽略。这对我来说是个问题,因为我喜欢将 Visual Studio 设置为在遇到任何抛出的异常时中断,因此每次我的应用程序启动时,我都会无缘无故地多次中断此异常。
如何防止抛出此异常?
只要网络上其他地方提到这个问题,建议通常涉及更改调试器设置以忽略它。这就好比去看医生说,“医生,医生,我的胳膊一抬起来就疼”,却被告知,“好吧,别再抬了。”我正在寻找一种解决方案,首先阻止抛出异常。
异常发生在 SetValue 方法中,因为它假设 GetValue 将首先被调用,而 Monitor.Enter 被调用。但是,LifetimeStrategy 和 UnityDefaultBehaviorExtension 类都会定期调用 SetValue 而不会调用 GetValue。
我宁愿不必更改源代码和维护我自己的 Unity 版本,所以我希望有一个解决方案,我可以向容器添加一些扩展、策略或策略的组合,以确保,如果生命周期管理器是 SynchronizedLifetimeManager,则始终先调用 GetValue。
câu trả lời hay nhất
我确信代码可以通过多种方式调用 SynchronizedLifetimeManager 或类似 ContainerControlledLifetimeManager 的后代,但有两种情况特别给我带来了问题。
首先是我自己的错——我使用构造函数注入(inject)来提供对容器的引用,并且在该构造函数中我还将类的新实例添加到容器中以供将来使用。这种向后的方法具有将生命周期管理器从 Transient 更改为 ContainerControlled 的效果,因此 Unity 在其上调用 GetValue 的对象与在其上调用 SetValue 的对象不同。吸取的教训是在构建期间不要做任何可能改变对象生命周期管理器的事情。
第二种情况是,每次调用 RegisterInstance 时,UnityDefaultBehaviorExtension 都会先调用 SetValue,而不会先调用 GetValue。幸运的是,Unity 具有足够的可扩展性,只要有足够的勇气,您就可以解决这个问题。
从这样的新行为扩展开始:
///
/// Replaces to eliminate
/// exceptions that would otherwise occur
/// when using RegisterInstance .
///
public class UnitySafeBehaviorExtension : UnityDefaultBehaviorExtension
{
///
/// Adds this extension's behavior to the container.
///
protected override void Initialize()
{
Context.RegisteringInstance += PreRegisteringInstance;
base.Initialize();
}
///
/// Handles the event by
/// ensuring that, if the lifetime manager is a
/// that its
/// method has been called.
///
/// The object responsible for raising the event.
/// A containing the
/// event's data.
private void PreRegisteringInstance(object sender, RegisterInstanceEventArgs e)
{
if (e.LifetimeManager is SynchronizedLifetimeManager)
{
e.LifetimeManager.GetValue();
}
}
}
那么您需要一种方法来替换默认行为。 Unity 没有删除特定扩展的方法,因此您必须删除所有内容并重新放回其他扩展:
public static IUnityContainer InstallCoreExtensions(this IUnityContainer container)
{
container.RemoveAllExtensions();
container.AddExtension(new UnityClearBuildPlanStrategies());
container.AddExtension(new UnitySafeBehaviorExtension());
#pragma warning disable 612,618 // Marked as obsolete, but Unity still uses it internally.
container.AddExtension(new InjectedMembers());
#pragma warning restore 612,618
container.AddExtension(new UnityDefaultStrategiesExtension());
return container;
}
注意到 UnityClearBuildPlanStrategies
了吗? RemoveAllExtensions 清除了容器的所有内部策略和策略列表,除了一个,所以我不得不使用另一个扩展来避免在恢复默认扩展时插入重复项:
///
/// Implements a that clears the list of
/// build plan strategies held by the container.
///
public class UnityClearBuildPlanStrategies : UnityContainerExtension
{
protected override void Initialize()
{
Context.BuildPlanStrategies.Clear();
}
}
现在您可以安全地使用 RegisterInstance 而不必担心被逼到疯狂的边缘。为了确定,这里有一些测试:
[TestClass]
public class UnitySafeBehaviorExtensionTests : ITest
{
private IUnityContainer Container;
private List FirstChanceExceptions;
[TestInitialize]
public void TestInitialize()
{
Container = new UnityContainer();
FirstChanceExceptions = new List();
AppDomain.CurrentDomain.FirstChanceException += FirstChanceExceptionRaised;
}
[TestCleanup]
public void TestCleanup()
{
AppDomain.CurrentDomain.FirstChanceException -= FirstChanceExceptionRaised;
}
private void FirstChanceExceptionRaised(object sender, FirstChanceExceptionEventArgs e)
{
FirstChanceExceptions.Add(e.Exception);
}
///
/// Tests that the default behavior of UnityContainer leads to a SynchronizationLockException
/// being throw on RegisterInstance .
///
[TestMethod]
public void UnityDefaultBehaviorRaisesExceptionOnRegisterInstance()
{
Container.RegisterInstance(this);
Assert.AreEqual(1, FirstChanceExceptions.Count);
Assert.IsInstanceOfType(FirstChanceExceptions[0], typeof(SynchronizationLockException));
}
///
/// Tests that UnitySafeBehaviorExtension protects against SynchronizationLockException s being
/// thrown during calls to RegisterInstance .
///
[TestMethod]
public void SafeBehaviorPreventsExceptionOnRegisterInstance()
{
Container.RemoveAllExtensions();
Container.AddExtension(new UnitySafeBehaviorExtension());
Container.AddExtension(new InjectedMembers());
Container.AddExtension(new UnityDefaultStrategiesExtension());
Container.RegisterInstance(this);
Assert.AreEqual(0, FirstChanceExceptions.Count);
}
}
public interface ITest { }
关于c# - Unity 可以一直不抛出 SynchronizationLockException 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2873767/
我刚开始使用企业库的 v5,似乎遇到了一些奇怪的问题。 像往常一样,我从日志记录开始。我刚刚添加了所需的引用并执行以下代码: Logger.Write("test"); 到目前为止没有什么特别的。检查
我有一个名为HandleMessage 的方法,启动了一个新线程来处理消息。如果成功获取锁对象,则进行处理。否则将消息放入队列。 SynchronizationLockException 总是在 Mo
这段代码有什么问题? 我总是得到一个 Object synchronization method was called from an unsynchronized block of code 异常(
我有以下代码,它基于 Monitor class example on the msdn website . private void WebRefresh_Click(object send
我正在尝试使用 SpinLock,但即使是单线程控制台应用程序中的这个最基本的代码,当我调用SpinLock.Exit() 时也会引发以下异常 System.Threading.Synchroniza
释放锁时我收到 SynchronizationLockException。 当然,我做的第一件事就是用谷歌搜索这个问题。我发现了两个主要的错误模式: 在与创建互斥锁不同的线程上释放互斥锁。 使用值类型
Unity 依赖项注入(inject)容器有一个似乎广为人知的问题,即 SynchronizedLifetimeManager 经常会导致 Monitor.Exit 方法抛出 Synchronizat
我正在使用 Monitor 类来管理关键部分。但有时我会遇到带有以下消息的 SynchronizationLockException An unhandled exception of type 'S
是否可以检测是否是同一个线程试图释放锁?我们在代码中有很多地方看起来像: try { try { if(!Monitor.TryEnter(obj, 2000))
我试图在 blazor(客户端)启动期间调用 api 以将语言翻译加载到 ILocalizer 中。 在这一点上,我尝试从 get 请求中获取 .Result blazor 在标题中引发错误。 这可以
我正在创建一段代码,从我们拥有的遗留系统中获取网页。为了避免过度查询,我缓存了获取到的URL。我正在使用 Monitor.Enter、Monitor.Exit 并仔细检查以避免发出两次请求,但是当使用
Tôi là một lập trình viên xuất sắc, rất giỏi!