如何将非一次性对象与每次冷观察对象绑定在一起? [英] How to bind a non-disposable object with each subscription of a cold observable?

查看:40
本文介绍了如何将非一次性对象与每次冷观察对象绑定在一起?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

很抱歉,以前是否有人问过这个问题,但我找不到重复的问题.也很抱歉最近提出了太多问题!我可能正在搜索自定义

Sorry if this question has been asked before, but I can't find a duplicate. Also sorry for asking too many questions lately! I am probably searching for a custom Observable.Using method, that is not restricted to disposable resources. What I have is a cold IObservable that maintains some internal state, for example a Random instance. This instance should be bound not with the IObservable itself, but with each of its subscriptions. Each subscriber should use a different instance of this resource. Take a look for example to the GetRandomNumbers method below:

static IObservable<int> GetRandomNumbers()
{
    var random = new Random(0);
    return Observable
        .Interval(TimeSpan.FromMilliseconds(100))
        .Select(x => random.Next(1, 10))
        .Take(10);
}

此方法生成10个随机数.RNG是用常量种子初始化的 Random 实例,因此它应始终产生相同的10个数字.但是,事实并非如此:

This method generates 10 random numbers. The RNG is a Random instance initialized with a constant seed, so it should produce always the same 10 numbers. But alas it doesn't:

var stream = GetRandomNumbers();
Console.WriteLine($"Results A: {String.Join(", ", await stream.ToArray())}");
Console.WriteLine($"Results B: {String.Join(", ", await stream.ToArray())}");

输出:

Results A: 7, 8, 7, 6, 2, 6, 9, 4, 9, 3
Results B: 3, 5, 6, 5, 9, 1, 8, 9, 7, 3

可观察到的 stream 的每个订户都有一组不同的数字!发生的是所有订阅者都使用相同的 Random 实例.这不仅是不希望的,而且还存在破坏对象内部状态的风险,因为 Random

Each subscriber of the stream observable gets a different set of numbers! What happens is that the same Random instance is used by all subscribers. This is not only undesirable, but it also creates the risk of corrupting the internal state of the object, since the Random class is not thread-safe.

我试图解决此问题的方法是使用 Using 运算符,该运算符具有 Func< TResource>resourceFactory 参数:

My attempt to solve this problem was to use the Using operator, that has a Func<TResource> resourceFactory parameter:

static IObservable<int> GetRandomNumbers()
{
    return Observable.Using(() => new Random(0), random =>
        Observable
            .Interval(TimeSpan.FromMilliseconds(100))
            .Select(x => random.Next(1, 10))
            .Take(10)
    );
}

如果 Random 是一次性的(我在一次性类中对其进行测试并按预期工作),这将是一个完美的解决方案,但事实并非如此,因此代码无法编译:

This would be a perfect solution if the Random was disposable (I tested it with a disposable class and worked as expected), but it's not, and so the code doesn't compile:

类型'System.Random'不能用作通用类型或方法'Observable.Using< TResult,TResource>(Func,Func< TResource,IObservable>)'中的类型参数'TResource'.没有从"System.Random"到"System.IDisposable"的隐式引用转换.

The type 'System.Random' cannot be used as type parameter 'TResource' in the generic type or method 'Observable.Using<TResult, TResource>(Func, Func<TResource, IObservable>)'. There is no implicit reference conversion from 'System.Random' to 'System.IDisposable'.

您能建议解决此问题的方法吗?

Could you suggest a solution to this problem?

推荐答案

Observable.Defer 是您的朋友,如果您希望每个用户保持状态.

Observable.Defer is your friend if you want per-subscriber state.

尝试一下:

static IObservable<int> GetRandomNumbers() =>
    Observable
        .Defer(() =>
        {
            var random = new Random(0);
            return Observable
                .Interval(TimeSpan.FromMilliseconds(100))
                .Select(x => random.Next(1, 10))
                .Take(10);
        });

我的结果:

Results A: 7, 8, 7, 6, 2, 6, 9, 4, 9, 3
Results B: 7, 8, 7, 6, 2, 6, 9, 4, 9, 3

这篇关于如何将非一次性对象与每次冷观察对象绑定在一起?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆