[UniRx] Give IReadOnlyReactiveCollection covariance
The other day, I was touching Unity and wanted to do something like the following.
interface IItemInfo{ ... }
class ItemInfo : IItemInfo{ ... }
class TestClass {
private ReactiveCollection<ItemInfo> m_rxCollection = new ReactiveCollection<ItemInfo>();
public IReadOnlyReactiveCollection<IItemInfo> ObservableCollection => m_rxCollection;
}
I want to publish a ReactiveCollection that stores an instance of a certain class as ReadOnly, but I also want to publish the contents as a __ interface instead of passing the class directly.
But if you do it normally, you will get angry.
However, for example, if you publish List
This is because the IReadOnlyList
Covariance is explained in detail on other sites, so I will omit it, but the point is that it is a function that allows polymorphism to be applied to __type arguments, and if you add the out modifier to __type arguments, it will be common. Degeneration can be used __.
The out modifier guarantees that the object of the type specified by the generics argument will not be changed, so if it is immutable, the type argument can also be safely type-converted.
The following site is very easy to understand and recommended for detailed explanations.
https://ufcpp.net/study/csharp/sp4_variance.html
So, if you look at the definition of the IReadOnlyList interface, the type argument has the out modifier.
On the other hand, if you look at the definition of the IReadOnlyReactiveCollection interface, the type argument does not have the out modifier.
So, if the IReadOnlyReactiveCollection
Give IReadOnlyReactiveCollection covariance
Let’s add the out modifier to the type argument of the interface of IReadOnlyReactiveCollection
The reason is that the members of the IReadOnlyReactiveCollection interface do not guarantee that T is immutable.
For example, CollectionAddEvent
T defines an immutable IReadOnlyCollectionAddEvent interface
So let’s define an interface IReadOnlyCollectionAddEvent
public interface IReadOnlyCollectionAddEvent<out T>
{
int Index { get; }
T Value { get; }
}
Removed T Setter. Originally it was a private set, so there should be no problem.
This ensures that T is invariant for operations performed through the IReadOnlyCollectionAddEvent interface, allowing covariance to be used on a sunny day.
Define the IReadOnlyReactiveCollectionOut interface
Do not rewrite the IReadOnlyReactiveCollection interface directly using the IReadOnlyCollectionAddEvent
Therefore, let’s define a new special IReadOnlyReactiveCollectionOut
public interface IReadOnlyReactiveCollectionOut<out T> : IEnumerable<T>
{
IObservable<IReadOnlyCollectionAddEvent<T>> ObserveAdd();
IObservable<IReadOnlyCollectionRemoveEvent<T>> ObserveRemove();
}
This time, I was only planning to use ObserveAdd () and ObserveRemove (), so I defined these two for the time being.
If you want to use other members, add them as appropriate.
Now implement this new IReadOnlyReactiveCollectionOut
IObservable<IReadOnlyCollectionAddEvent<T>> IReadOnlyReactiveCollectionOut<T>.ObserveAdd()
=> ObserveAdd().Select(d => (IReadOnlyCollectionAddEvent<T>)d);
IObservable<IReadOnlyCollectionRemoveEvent<T>> IReadOnlyReactiveCollectionOut<T>.ObserveRemove()
=> ObserveRemove().Select(d => (IReadOnlyCollectionRemoveEvent<T>)d);
It’s been a little long, but now you can “publish the ReactiveCollection
Try using
The code in question
I want to make ReactiveCollection
This is because the IReadOnlyReactiveCollection
Improved code
On the other hand, if you publish with the countermeasure IReadOnlyReactiveCollectionOut
No more errors!
That’s because the IReadOnlyReactiveCollectionOut
Finally
I think that there are many cases where the ReactiveCollection is published as ReadOnly, but this time I wanted to publish the contents class as an interface, so I tried to take measures.
I hope it is supported by the UniRx standard …
There is no problem so far, but I will write an article if any inconvenience arises in the future.