小编Dan*_*ant的帖子

确定是否由于抛出异常而在finally块中执行

是否可以通过finally抛出异常来确定代码当前是否在处理程序的上下文中执行?我非常喜欢使用IDisposable模式来实现入口/出口作用域功能,但是这种模式的一个问题是,如果在主体中发生异常,您可能不一定希望发生作用域结束行为using.我会找这样的东西:

public static class MyClass
{
    public static void MyMethod()
    {
        using (var scope = MyScopedBehavior.Begin())
        {
            //Do stuff with scope here
        }
    }
}

public sealed class MyScopedBehavior : IDisposable
{
    private MyScopedBehavior()
    {
        //Start of scope behavior
    }

    public void Dispose()
    {
        //I only want to execute the following if we're not unwinding
        //through finally due to an exception:
        //...End of scope behavior    
    }

    public static MyScopedBehavior Begin()
    {
        return new MyScopedBehavior(); …
Run Code Online (Sandbox Code Playgroud)

c# idisposable exception finally try-catch

33
推荐指数
4
解决办法
7556
查看次数

使用async/await进行资源锁定

我有一个应用程序,我有一个共享资源(一个运动系统),可以由多个客户端访问.我有个别操作需要在移动期间访问系统,如果同时请求冲突操作,则应该抛出"忙"异常.我也有序列发生器需要获得对Motion系统的独占访问权,以执行多个操作,并穿插其他操作; 在整个序列中,没有其他客户端应该能够运行操作.

我传统上使用Thread-affinity接近它,因此Thread可以请求独占访问并运行与操作相对应的阻塞调用.虽然线程具有访问权限,但没有其他线程可以使用该资源.我现在遇到的问题是我已经开始使用async/await模式实现我的系统,以允许更清晰的序列器实现.问题是现在我的音序器并不总是在同一个线程上运行; 活动线程可以在回调过程中发生变化,因此不再容易确定我是否处于有效的上下文中以保持运行操作.一个注意事项是一些操作本身由等待组成,这意味着序列和单个操作都可以跨越多个线程.

我的问题:是否有人知道一个好的模式来处理由于异步/等待而存在线程切换时获取独占访问权限?

作为参考,我考虑过一些事情:

  1. 我可以创建一个自定义的SynchronizationContext,它将序列持续时间内的所有sequencer调用封送回单个Thread.这样可以让我重用现有的线程相关访问管理代码.缺点是每当我执行一个序列或操作时,这将需要专用一个线程(因为操作也可以跨越多个线程.)

  2. 创建一个可获取的访问令牌以传递给Operation方法,以证明您已获得访问权限.这具有使用令牌参数膨胀方法的缺点.

  3. 使用(2)中的访问令牌方法,但为Operations接口创建一个重复的接口实现,以便可以使用令牌"烘焙"实例化包装器.这会创建一些丑陋的胶水代码,但它会清除序列代码,以便它不再需要将令牌传递给每个方法.

.net c# synchronization locking async-await

32
推荐指数
2
解决办法
2万
查看次数

MVVM的Resharper警告

当我用WPF实现MVVM模式时,我发现Resharper经常警告我某些属性从未在我的ViewModels中使用过.问题是它们正在被使用,但只能由数据绑定系统使用.有没有其他人遇到过这种烦恼,有没有办法帮助Resharper意识到这些属性确实被使用了?至少,我很高兴VS 2010正确地认识到[Import]标记的成员不会"永远为空",但希望我也可以解决这个问题.

c# wpf resharper warnings mvvm

26
推荐指数
3
解决办法
5325
查看次数

MVVM:如何处理嵌套的ViewModel之间的交互?

我一直在试验经常提到的MVVM模式,在某些情况下我很难定义清晰的界限.在我的应用程序中,我有一个对话框,允许我创建到Controller的连接.对话框有一个ViewModel类,这很简单.但是,该对话框还包含一个附加控件(由a选择ContentTemplateSelector),该控件根据所连接的控制器的特定类型而变化.此控件具有自己的ViewModel.

我遇到的问题是,当我按OK键关闭对话框时,我需要实际创建请求的连接,这需要在内部Controller特定的ViewModel类中捕获的信息.简单地让所有特定于Controller的ViewModel类实现构建连接的公共接口是很诱人的,但是内部ViewModel是否应该真正负责这种构造?

我的一般问题是:是否有任何普遍接受的设计模式可用于ViewModel如何与彼此进行交互,特别是当"父"VM需要来自"子"VM的帮助以便知道该怎么做?


编辑:

我确实想出了一个比我原先想的更清洁的设计,但我仍然不确定这是否是'正确'的方法.我有一些后端服务,允许ContentTemplateSelector查看Controller实例并伪魔术地找到要为连接构建器显示的控件.让我烦恼的是,我的顶级ViewModel必须查看DataContext生成的控件并将其转换为适当的界面,这似乎是一个坏主意(为什么View DataContext与创建连接有关? ?)

我结束了这样的事情(简化):

public interface IController
{
    IControllerConnectionBuilder CreateConnectionBuilder();
}

public interface IControllerConnectionBuilder
{
    ControllerConnection BuildConnection();
}
Run Code Online (Sandbox Code Playgroud)

我有我的内部ViewModel类实现IControllerConnectionBuilder,Controller返回内部ViewModel.顶级ViewModel然后可视化IControllerConnectionBuilder(通过伪魔法机制).它仍然困扰我一点,这是我的内部ViewModel执行构建,但至少现在我的顶级ViewModel不必知道脏细节(它甚至不知道或不关心可视化控件正在使用视图模型).

如果有办法进一步清理这个问题,我欢迎提出更多想法.我仍然不清楚ViewModel对于它有多大的责任.

c# architecture mvvm

18
推荐指数
1
解决办法
4198
查看次数

当不能简单地过载时,混合可选参数和参数

此问题类似,我想将可选参数与params关键字混合,这当然会产生歧义.不幸的是,创建重载的答案不起作用,因为我想利用调用者信息属性,如下所示:

    public void Info(string message, [CallerMemberName] string memberName = "", 
                     [CallerLineNumber] int lineNumber = 0, params object[] args)
    {
        _log.Info(BuildMessage(message, memberName, lineNumber), args);
    }
Run Code Online (Sandbox Code Playgroud)

在没有可选参数的情况下创建重载会更改调用站点,从而阻止这些特定参数正常工作.

我找到了一个几乎可以工作的解决方案(虽然很难看):

    public void Info(string message, object arg0, [CallerMemberName] string memberName = "",
                     [CallerLineNumber] int lineNumber = 0)
    {
        _log.Info(BuildMessage(message, memberName, lineNumber), arg0);
    }

    public void Info(string message, object arg0, object arg1, [CallerMemberName] string memberName = "",
                     [CallerLineNumber] int lineNumber = 0)
    {
        _log.Info(BuildMessage(message, memberName, lineNumber), arg0, arg1);
    }
Run Code Online (Sandbox Code Playgroud)

这里的问题是,如果为最后一个参数指定一个字符串,则重载决策假定您打算memberName在重载中显式指定需要较少的参数,这不是所需的行为.

有没有办法实现这一点(也许使用一些我没有学过的新属性?)或者我们是否只是达到了自动魔法编译器支持可以给我们的极限?

.net c# optional-parameters params callermembername

14
推荐指数
2
解决办法
3585
查看次数

在代码合同中使用Contract.ForAll

好的,我还有另一个Code Contracts问题.我有一个接口方法的合同,看起来像这样(为清楚起见省略了其他方法):

[ContractClassFor(typeof(IUnboundTagGroup))]
public abstract class ContractForIUnboundTagGroup : IUnboundTagGroup
{
    public IUnboundTagGroup[] GetAllGroups()
    {
        Contract.Ensures(Contract.Result<IUnboundTagGroup[]>() != null);
        Contract.Ensures(Contract.ForAll(Contract.Result<IUnboundTagGroup[]>(), g => g != null));

        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

我有代码消耗这样的接口:

    public void AddRequested(IUnboundTagGroup group)
    {
            foreach (IUnboundTagGroup subGroup in group.GetAllGroups())
            {
                AddRequested(subGroup);
            }
            //Other stuff omitted
    }
Run Code Online (Sandbox Code Playgroud)

AddRequested需要一个非空输入参数(它实现具有需要契约的接口),所以我得到了"需要得到证实:组= NULL"在亚错误被传递到AddRequested.我正确使用ForAll语法吗?如果是这样,并在求解根本不理解,有另一种方式来帮助求解承认合同或者我只需要使用时GetAllGroups()被调用的假设?

c# static-analysis code-contracts forall

12
推荐指数
1
解决办法
1708
查看次数

在C#中使用"dynamic"来实现访问者模式

我有一个应用程序,我在一系列元素上执行操作,操作的确切性质取决于所操作元素的类型.由于封装的原因,元素不适合实现操作; 这意味着它不能是元素类型的虚方法,所以'标准'多态不起作用.我提出了一个与之相关的问题,并被告知这被称为访客模式.

我以前总是使用if/elseif基于对象类型的调度程序方法实现它,然后调用适当的实现.然而,最近,我注意到同样的事情可能是使用dynamic关键字完成,如下所示:

private void ReconcileTips()
{
    foreach (var step in _definition.Steps)
    {
        ReconcileTips((dynamic)step);
    }
}

private void ReconcileTips(IBulkDispenseDefinition bulkDispense)
{
    bulkDispense.TipType = ReconcileTip(bulkDispense.TipType);
}

private void ReconcileTips(ImportScreenDefinition importScreen)
{
    foreach (var usage in importScreen.ReagentUsages)
        usage.TipType = ReconcileTip(usage.TipType);
}

private void ReconcileTips(BuildScreenDefinition buildScreen)
{
    foreach (var function in buildScreen.Functions)
        function.TipType = ReconcileTip(function.TipType);
}
Run Code Online (Sandbox Code Playgroud)

类似的模式可以用于与类结构并行的其他操作,比如为每个元素创建视图模型_definition.Steps.我们的想法是,编译器基本上将其转换为if/elseif我之前编写的相同逻辑,从而节省了我的努力.那么,有几个问题:

  1. 动态调度是否有任何问题我没有考虑过?我相信这相当于执行一系列if (x is TypeA) Do((TypeA)x) else...,但我可能是错的.

  2. 这比较长的if/elseif方法更清洁,更容易理解吗?

.net c# dynamic visitor

11
推荐指数
2
解决办法
1819
查看次数

MVVM:瘦ViewModels和Rich Models

我将继续努力克服MVVM模式,并且在尝试为小型/中型项目创建实用设计时,遇到了许多挑战.其中一个挑战是弄清楚如何在不创建大量重复,难以维护的代码的情况下获得与此模式解耦的好处.

我目前的策略是创建"丰富"的模型类.他们充分意识到它们将被MVVM模式消耗并实现INotifyPropertyChanged,允许观察它们的集合并且仍然认识到它们可能总是被观察.我的ViewModel类往往很薄,只在实际需要转换数据时暴露属性,其大部分代码是RelayCommand处理程序.视图可以直接绑定到ViewModel或Models,具体取决于是否需要进行任何数据转换.我使用AOP(通过Postsharp)来缓解INotifyPropertyChanged的痛苦,这样就可以很容易地以这种方式使我的所有Model类"丰富".

使用这种方法有明显的缺点吗?我可以假设ViewModel和View是如此紧密耦合,如果我需要View的新数据转换,我可以根据需要将其添加到ViewModel中吗?

c# wpf model mvvm

10
推荐指数
1
解决办法
1459
查看次数

收集合同和线程

假设我有一个自定义集合类,它提供了一些内部线程同步.例如,简化的Add方法可能如下所示:

    public void Add(T item)
    {
        _lock.EnterWriteLock();
        try
        {
            _items.Add(item);
        }
        finally
        {
            _lock.ExitWriteLock();
        }
    }
Run Code Online (Sandbox Code Playgroud)

最新的Code Contracts抱怨说CodeContracts: ensures unproven: this.Count >= Contract.OldValue(this.Count).问题是这真的无法证明.我可以确保在内部锁定内,Count将大于其先前的值.但是,在方法的退出处,我无法确保这一点.退出锁之后,在方法完成之前,另一个线程可以发出两个Removes(可能是不同的元素),使合同无效.

这里的基本问题是,只有在整个应用程序中一致地使用锁定以对集合进行所有访问时,才能认为集合合同在特定锁定上下文中是有效的.我的集合必须在多个线程中使用(非冲突的Add和Remove是一个有效的用例),但我仍然希望实现ICollection<T>.即使我知道我不能,我是否应该假装我能够满足这个确保要求的假设?令我印象深刻的是,BCL系列中没有一个能够真正确保这一点.


编辑:

基于一些进一步的调查,听起来最大的问题是合同重写者可能引入不正确的断言,导致运行时失败.基于此,我认为我唯一的选择是限制我的接口实现IEnumerable<T>,因为合同ICollection<T>暗示实现类不能提供内部线程同步(访问必须始终在外部同步.)这对我的特定情况是可接受的(所有客户端)希望改变集合直接了解类类型,但我很想知道是否有其他解决方案.

c# static-analysis code-contracts

9
推荐指数
1
解决办法
420
查看次数

有效的信令任务TPL完成频繁重新启动事件

我正在研究一个模拟系统,除其他外,它允许在离散的模拟时间步骤中执行任务.执行都发生在模拟线程的上下文中,但是,从使用系统的"操作员"的角度来看,它们希望表现为异步.值得庆幸的是,TPL具有方便的'async/await'关键字,这使得它非常简单.我在模拟上有一个原始方法,如下所示:

    public Task CycleExecutedEvent()
    {
        lock (_cycleExecutedBroker)
        {
            if (!IsRunning) throw new TaskCanceledException("Simulation has been stopped");
            return _cycleExecutedBroker.RegisterForCompletion(CycleExecutedEventName);
        }
    }
Run Code Online (Sandbox Code Playgroud)

这基本上是创建一个新的TaskCompletionSource然后返回一个Task.此任务的目的是在模拟发生新的"ExecuteCycle"时执行其继续.

然后我有一些像这样的扩展方法:

    public static async Task WaitForDuration(this ISimulation simulation, double duration)
    {
        double startTime = simulation.CurrentSimulatedTime;
        do
        {
            await simulation.CycleExecutedEvent();
        } while ((simulation.CurrentSimulatedTime - startTime) < duration);
    }

    public static async Task WaitForCondition(this ISimulation simulation, Func<bool> condition)
    {
        do
        {
            await simulation.CycleExecutedEvent();
        } while (!condition());
    }
Run Code Online (Sandbox Code Playgroud)

这些非常方便,从"运营商"角度构建序列,根据条件采取行动并等待模拟时间段.我遇到的问题是CycleExecuted非常频繁地发生(如果我以完全加速的速度运行,大约每隔几毫秒).因为这些'wait'辅助方法在每个循环中注册一个新的'await',这会导致TaskCompletionSource实例中的大量转换.

我已经分析了我的代码,并且我发现大约5.5%的总CPU时间花费在这些完成中,其中"活动"代码中只花费了可忽略不计的百分比.实际上,所有时间都花在注册新的完成上,同时等待触发条件有效.

我的问题:我如何在保持async/await模式的便利性的同时提高写入"操作员行为"的性能?我认为我需要像轻量级和/或可重复使用的TaskCompletionSource这样的东西,因为触发事件经常发生.


我一直在做更多的研究,听起来一个很好的选择是创建Awaitable模式的自定义实现,它可以直接绑定到事件,消除了对一堆TaskCompletionSource和Task实例的需要.它在这里有用的原因是有很多不同的延续等待CycleExecutedEvent,他们需要经常等待它.理想情况下,我正在寻找一种方法来排队延续回调,然后在事件发生时回调队列中的所有内容.我会继续挖掘,但如果人们知道一个干净的方法,我欢迎任何帮助.


对于将来浏览这个问题的人来说,这是我放在一起的定制等待者:

public sealed class CycleExecutedAwaiter : INotifyCompletion
{
    private readonly …
Run Code Online (Sandbox Code Playgroud)

.net c# task-parallel-library async-await

9
推荐指数
2
解决办法
2747
查看次数