如果数组元素发生变化则可观察
Observable if the array element is changed
如何用一行代码写出这段代码?
public class RadGridColumnObservable
{
public RadGridColumnObservable(RadGridView grid, IMessageBus messageBus)
{
this.grid = grid;
this.messageBus = messageBus;
}
public IDisposable Initialize()
{
CreateStates();
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(_ => CheckUp());
}
//
private readonly RadGridView grid;
private readonly IMessageBus messageBus;
private readonly List<bool> states = new List<bool>();
//
private void CreateStates()
{
states.Clear();
states.AddRange(grid.Columns.Select(it => it.IsVisible));
}
private void CheckUp()
{
if (states.SequenceEqual(grid.Columns.Select(it => it.IsVisible))) return;
CreateStates();
messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged));
}
}
想法是:我想检查IsVisible
属性是否改变了。
我不喜欢用这条线:
private readonly List<bool> states = new List<bool>();
您可以通过以下方式获得 IsVisible
值:
private IObservable<List<bool>> CreateStatesObservable()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Select(_ => grid.Columns.Select(it => it.IsVisible));
}
然后使用 Scan 来跟踪您之前的值:
public void Initialize()
{
var observable =
CreateStatesObservable()
.Scan(
(prev: default(List<bool>), actual: default(List<bool>)),
(acc, c) => (acc.actual, current))
.Where(values => !values.actual.SequenceEqual(values.prev))
.Select(_ => true);
}
或者您可以使用 Defer 并执行如下操作:
public void Initialize2()
{
var observable = CreateStatesObservable();
var deferred =
Observable.Defer(
() =>
{
List<bool> previous = null;
return observable.Select(
values =>
{
if (previous is null)
{
previous = values;
return false;
}
if (!values.SequenceEqual(previous))
{
previous = values;
return true;
}
return false;
});
})
.Where(value => value);
}
这两个选项都应该为您提供一个可观察对象,它仅在其中一列 IsVisible
发生更改时才产生一个值。 (该值只是 true
)
编辑:
您也可以像这样将 DistinctUntilChanged()
与您自己的 IEqualityComparer
一起使用:
class ListComparer : IEqualityComparer<List<bool>>
{
bool IEqualityComparer<List<bool>>.Equals(List<bool>? a, List<bool>? b)
{
if (a is null && b is null)
{
return true;
}
if (a is null || b is null)
{
return false;
}
return a.SequenceEqual(b);
}
int IEqualityComparer<List<bool>>.GetHashCode(List<bool> obj)
{
return obj.GetHashCode();
}
}
然后像这样使用它:
public void Initialize()
{
var observable =
CreateStatesObservable()
.DistinctUntilChanged(new ListComparer())
.Select(_ => true);
}
我现在用的是这样的:
public class RadGridColumnObservable
{
public RadGridColumnObservable(RadGridView grid, IMessageBus messageBus)
{
this.grid = grid;
this.messageBus = messageBus;
}
public IDisposable Initialize()
{
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Scan((prev: grid.Columns.Select(it => it.IsVisible).ToList(), actual: grid.Columns.Select(it => it.IsVisible).ToList()),
(acc, c) =>
{
if (!acc.prev.SequenceEqual(acc.actual))
acc.prev = acc.actual;
acc.actual = grid.Columns.Select(it => it.IsVisible).ToList();
return acc;
})
.Where(it => !it.prev.SequenceEqual(it.actual))
.Subscribe(it => messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged)));
}
//
private readonly RadGridView grid;
private readonly IMessageBus messageBus;
}
但我不喜欢,因为我第二次使用“SequenceEqual”。
我想你可以将你的 Initialize()
调整成这样:
public IDisposable Initialize()
{
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Select(v => grid.Columns.Select(it => it.IsVisible).ToList())
.Scan((prev: new List<bool>(), actual: new List<bool>()),
(acc, c) => (acc.actual, c))
.Where(it => !it.actual.SequenceEqual(it.prev))
.Subscribe(_ => messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged)));
}
这应该会给你相同的结果,你只需要 SequenceEqual()
一次。扫描就在那里,所以你有“当前”和“以前”的价值。在你的情况下,你真的不需要在里面做检查。
如何用一行代码写出这段代码?
public class RadGridColumnObservable
{
public RadGridColumnObservable(RadGridView grid, IMessageBus messageBus)
{
this.grid = grid;
this.messageBus = messageBus;
}
public IDisposable Initialize()
{
CreateStates();
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Subscribe(_ => CheckUp());
}
//
private readonly RadGridView grid;
private readonly IMessageBus messageBus;
private readonly List<bool> states = new List<bool>();
//
private void CreateStates()
{
states.Clear();
states.AddRange(grid.Columns.Select(it => it.IsVisible));
}
private void CheckUp()
{
if (states.SequenceEqual(grid.Columns.Select(it => it.IsVisible))) return;
CreateStates();
messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged));
}
}
想法是:我想检查IsVisible
属性是否改变了。
我不喜欢用这条线:
private readonly List<bool> states = new List<bool>();
您可以通过以下方式获得 IsVisible
值:
private IObservable<List<bool>> CreateStatesObservable()
{
return Observable.Interval(TimeSpan.FromSeconds(1))
.Select(_ => grid.Columns.Select(it => it.IsVisible));
}
然后使用 Scan 来跟踪您之前的值:
public void Initialize()
{
var observable =
CreateStatesObservable()
.Scan(
(prev: default(List<bool>), actual: default(List<bool>)),
(acc, c) => (acc.actual, current))
.Where(values => !values.actual.SequenceEqual(values.prev))
.Select(_ => true);
}
或者您可以使用 Defer 并执行如下操作:
public void Initialize2()
{
var observable = CreateStatesObservable();
var deferred =
Observable.Defer(
() =>
{
List<bool> previous = null;
return observable.Select(
values =>
{
if (previous is null)
{
previous = values;
return false;
}
if (!values.SequenceEqual(previous))
{
previous = values;
return true;
}
return false;
});
})
.Where(value => value);
}
这两个选项都应该为您提供一个可观察对象,它仅在其中一列 IsVisible
发生更改时才产生一个值。 (该值只是 true
)
编辑:
您也可以像这样将 DistinctUntilChanged()
与您自己的 IEqualityComparer
一起使用:
class ListComparer : IEqualityComparer<List<bool>>
{
bool IEqualityComparer<List<bool>>.Equals(List<bool>? a, List<bool>? b)
{
if (a is null && b is null)
{
return true;
}
if (a is null || b is null)
{
return false;
}
return a.SequenceEqual(b);
}
int IEqualityComparer<List<bool>>.GetHashCode(List<bool> obj)
{
return obj.GetHashCode();
}
}
然后像这样使用它:
public void Initialize()
{
var observable =
CreateStatesObservable()
.DistinctUntilChanged(new ListComparer())
.Select(_ => true);
}
我现在用的是这样的:
public class RadGridColumnObservable
{
public RadGridColumnObservable(RadGridView grid, IMessageBus messageBus)
{
this.grid = grid;
this.messageBus = messageBus;
}
public IDisposable Initialize()
{
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Scan((prev: grid.Columns.Select(it => it.IsVisible).ToList(), actual: grid.Columns.Select(it => it.IsVisible).ToList()),
(acc, c) =>
{
if (!acc.prev.SequenceEqual(acc.actual))
acc.prev = acc.actual;
acc.actual = grid.Columns.Select(it => it.IsVisible).ToList();
return acc;
})
.Where(it => !it.prev.SequenceEqual(it.actual))
.Subscribe(it => messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged)));
}
//
private readonly RadGridView grid;
private readonly IMessageBus messageBus;
}
但我不喜欢,因为我第二次使用“SequenceEqual”。
我想你可以将你的 Initialize()
调整成这样:
public IDisposable Initialize()
{
return Observable
.Interval(TimeSpan.FromSeconds(1))
.Select(v => grid.Columns.Select(it => it.IsVisible).ToList())
.Scan((prev: new List<bool>(), actual: new List<bool>()),
(acc, c) => (acc.actual, c))
.Where(it => !it.actual.SequenceEqual(it.prev))
.Subscribe(_ => messageBus.Publish(new NotifyMessage(MessageTypes.HistoryColumnsChanged)));
}
这应该会给你相同的结果,你只需要 SequenceEqual()
一次。扫描就在那里,所以你有“当前”和“以前”的价值。在你的情况下,你真的不需要在里面做检查。