小编And*_*son的帖子

Rx:我如何立即响应,并限制后续请求

我想建立一个可以立即响应事件的Rx订阅,然后忽略在指定的"冷却"时段内发生的后续事件.

开箱即用的Throttle/Buffer方法仅在超时过后响应,这不是我需要的.

下面是一些设置场景的代码,并使用Throttle(这不是我想要的解决方案):

class Program
{
    static Stopwatch sw = new Stopwatch();

    static void Main(string[] args)
    {
        var subject = new Subject<int>();
        var timeout = TimeSpan.FromMilliseconds(500);

        subject
            .Throttle(timeout)
            .Subscribe(DoStuff);

        var factory = new TaskFactory();

        sw.Start();

        factory.StartNew(() =>
        {
            Console.WriteLine("Batch 1 (no delay)");
            subject.OnNext(1);
        });

        factory.StartNewDelayed(1000, () =>
        {
            Console.WriteLine("Batch 2 (1s delay)");
            subject.OnNext(2);
        });

        factory.StartNewDelayed(1300, () =>
        {
            Console.WriteLine("Batch 3 (1.3s delay)");
            subject.OnNext(3);
        });

        factory.StartNewDelayed(1600, () =>
        {
            Console.WriteLine("Batch 4 (1.6s delay)");
            subject.OnNext(4);
        });

        Console.ReadKey();
        sw.Stop();
    }

    private static void …
Run Code Online (Sandbox Code Playgroud)

c# system.reactive

27
推荐指数
3
解决办法
5572
查看次数

在TPL中中止长时间运行的任务

我们的应用程序使用TPL来序列化(可能)长时间运行的工作单元.工作(任务)的创建是用户驱动的,可以随时取消.为了拥有响应式用户界面,如果不再需要当前的工作,我们想放弃我们正在做的事情,并立即开始另一项任务.

任务排队等同于:

private Task workQueue;
private void DoWorkAsync
    (Action<WorkCompletedEventArgs> callback, CancellationToken token) 
{
   if (workQueue == null)
   {
      workQueue = Task.Factory.StartWork
          (() => DoWork(callback, token), token);
   }
   else 
   {
      workQueue.ContinueWork(t => DoWork(callback, token), token);
   }
}
Run Code Online (Sandbox Code Playgroud)

DoWork方法包含长时间运行的呼叫,因此,token.IsCancellationRequested如果/当检测到取消时,它不会像不断检查状态和挽救一样简单.长时间运行的工作将阻止任务继续,直到它完成,即使任务被取消.

我已经提出了两个样本方法来解决这个问题,但我不相信这两种方法都是正确的.我创建了简单的控制台应用程序来演示它们如何工

需要注意的重要一点是,在原始任务完成之前会继续触发.

尝试#1:内部任务

static void Main(string[] args)
{
   CancellationTokenSource cts = new CancellationTokenSource();
   var token = cts.Token;
   token.Register(() => Console.WriteLine("Token cancelled"));
   // Initial work
   var t = Task.Factory.StartNew(() =>
     {
        Console.WriteLine("Doing work");

      // Wrap the long running …
Run Code Online (Sandbox Code Playgroud)

c# task-parallel-library cancellation

17
推荐指数
1
解决办法
8388
查看次数

在长时间运行的单元测试中协调取消

我正在为我的应用程序的"粘合"层编写单元测试,并且很难为异步方法创建确定性测试,允许用户过早地取消操作.

具体来说,在一些异步方法中,我们有代码响应取消调用并确保对象在完成之前处于正确状态.我想确保测试涵盖这些代码路径.

在此场景中举例说明典型异步方法的一些C#伪代码如下:

public void FooAsync(CancellationToken token, Action<FooCompletedEventArgs> callback) 
{
   if (token.IsCancellationRequested) DoSomeCleanup0();

   // Call the four helper methods, checking for cancellations in between each
   Exception encounteredException;
   try
   {
      MyDependency.DoExpensiveStuff1();
      if (token.IsCancellationRequested) DoSomeCleanup1();

      MyDependency.DoExpensiveStuff2();
      if (token.IsCancellationRequested) DoSomeCleanup2();

      MyDependency.DoExpensiveStuff3();
      if (token.IsCancellationRequested) DoSomeCleanup3();

      MyDependency.DoExpensiveStuff4();
      if (token.IsCancellationRequested) DoSomeCleanup4();

   }
   catch (Exception e)
   {
      encounteredException = e;
   }

   if (!token.IsCancellationRequested)
   {
      var args = new FooCompletedEventArgs(a bunch of params);
      callback(args);
   }
}
Run Code Online (Sandbox Code Playgroud)

到目前为止,我提出的解决方案涉及模拟MyDependency由胶层包裹的基础操作,并强制每个人在任意时间段内休眠.然后我调用异步方法,并告诉我的单元测试在取消异步请求之前休眠几毫秒.

像这样的东西(以Rhino Mocks为例):

[TestMethod]
public void FooAsyncTest_CancelAfter2()
{
   // arrange …
Run Code Online (Sandbox Code Playgroud)

unit-testing asynchronous mocking

8
推荐指数
1
解决办法
797
查看次数

C#中的通用继承:无法将类型'MyWidget'隐式转换为'IWidget'

我在使用泛型设置继承时遇到问题.

本质上我想要做的是拥有一个本身接受接口的通用接口.棘手的部分是"内部"界面可以在其上面分层更具体的界面.

以下是我正在尝试构建的结构的代表性示例:

public interface IThing  { }

public interface IMoreSpecificThing : IThing  {  }

public interface IWidget<T> where T : IThing  {  }

public class MySpecificThing : IMoreSpecificThing { }

public class MyWidget : IWidget<MySpecificThing> { }

public class MyClass
{
    public IWidget<IThing> MyProperty { get; set; }

    public MyClass()
    {
        MyProperty = new MyWidget();
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,当我将MyWidget分配给MyProperty时,我收到以下错误:

无法隐式转换'MyWidget''IWidget<IThing>'.存在显式转换(您是否错过了演员?)

我做错了什么,有没有办法正确地做到这一点?

c# generics inheritance

3
推荐指数
1
解决办法
699
查看次数

使用FromAsyncPattern进行单元测试

Reactive Extensions有一个性感的小钩子来简化调用异步方法:

var func = Observable.FromAsyncPattern<InType, OutType>(
    myWcfService.BeginDoStuff,
    myWcfService.EndDoStuff);

func(inData).ObserveOnDispatcher().Subscribe(x => Foo(x));
Run Code Online (Sandbox Code Playgroud)

我在WPF项目中使用它,它在运行时运行良好.

不幸的是,当尝试使用这种技术的单元测试方法时,我遇到了随机故障.包含此代码的测试的每五次执行中约有3次失败.

这是一个示例测试(使用Rhino/unity自动模拟容器实现):

[TestMethod()]
public void SomeTest()
{
   // arrange
   var container = GetAutoMockingContainer();

   container.Resolve<IMyWcfServiceClient>()
      .Expect(x => x.BeginDoStuff(null, null, null))
      .IgnoreArguments()
      .Do(
         new Func<Specification, AsyncCallback, object, IAsyncResult>((inData, asyncCallback, state) =>
            {
               return new CompletedAsyncResult(asyncCallback, state);
             }));

   container.Resolve<IRepositoryServiceClient>()
      .Expect(x => x.EndDoStuff(null))
      .IgnoreArguments()
      .Do(
         new Func<IAsyncResult, OutData>((ar) =>
         {
            return someMockData;
         }));

   // act
   var target = CreateTestSubject(container);

   target.DoMethodThatInvokesService();

   // Run the dispatcher for everything over background priority
   Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.Background, new …
Run Code Online (Sandbox Code Playgroud)

.net c# wpf unit-testing system.reactive

2
推荐指数
1
解决办法
1595
查看次数