I'm looking at CompositeDisposable docs and it says that .dispose() is idempotent. Is .add() also idempotent?
CompositeDisposable compositeDisposable = ...
Disposable disposable = ...
compositeDisposable.add(disposable);
compositeDisposable.add(disposable);
compositeDisposable.add(disposable);
How many Disposables is compositeDisposable tracking? I see that its backed by an OpenHashSet but it's not very clear how OpenHashSet.add() works.
The documentation is copied from Disposable.dispose() and a suggestion to the developer implementing it. And of course they made CompositeDisposable.dispose() idempotent as well.
For CompositeDisposable.add(Disposable) you already noticed that it's backed by an OpenHashSet. As this is a Set "implementation", it ensures that elements are only added once, thus add() is idempotent for both classes.
Related
If I have this rxjava chain:
Observable.create { ... }
.firstElement()
.subscribe( {...}, {...})
After experimenting and looking at the sources, it looks like firstElement() automatically dispose the up stream (which makes sense), so I don't have to care about it. Is that right?
Ok then. My question is, should I dispose the Maybe returned by firstElement()?
I put a .doOnDispose() callback after firstElement() and checked that it doesn't happen automatically. Does that mean that I shouldn't care? If a Maybe can emit no more than one item
Short answer: You should don't care.
Longer answer: doOnDispose() is only called when Observable is disposed explicitly (by disposable.dispose()) but it will not be invoked when Observable calls onComplete(). If you want to check it by yourself instead of doOnDispose() you should us doFinally().
Peace!
I have some code in a class that takes FileSystemWatcher events and flattens them into an event in my domain:
(Please note, the *AsObservable methods are extensions from elsewhere in my project, they do what they say 🙂.)
watcher = new FileSystemWatcher(ConfigurationFilePath);
ChangeObservable = Observable
.Merge(
watcher.ChangedAsObservable().Select((args) =>
{
return new ConfigurationChangedArgs
{
Type = ConfigurationChangeType.Edited,
};
}),
watcher.DeletedAsObservable().Select((args) =>
{
return new ConfigurationChangedArgs
{
Type = ConfigurationChangeType.Deleted,
};
}),
watcher.RenamedAsObservable().Select((args) =>
{
return new ConfigurationChangedArgs
{
Type = ConfigurationChangeType.Renamed,
};
})
);
ChangeObservable.Subscribe((args) =>
{
Changed.Invoke(this, args);
});
Something that I'm trying to wrap my head around as I'm learning are best practices around naming, ownership and cleanup of the IObservable and IDisposable returned by code like this.
So, some specific questions:
Is it okay to leak IObservables from a class that creates them? For example, is the property I'm assigning this chain to okay to be public?
Does the property name ChangeObservable align with what most people would consider best practice when using the .net reactive extensions?
Do I need to call Dispose on any of my subscriptions to this chain, or is it safe enough to leave everything up to garbage collection when the containing class goes out of scope? Keep in mind, I'm observing events from watcher, so there's some shared lifecycle there.
Is it okay to take an observable and wire them into an event on my own class (Changed in the example above), or is the idea to stay out of the native .net event system and leak my IObservable?
Other tips and advice always appreciated! 😀
Is it okay to leak IObservables from a class that creates them? For
example, is the property I'm assigning this chain to okay to be
public?
Yes.
Does the property name ChangeObservable align with what most
people would consider best practice when using the .net reactive
extensions?
Subjective question. Maybe FileChanges? The fact that it's an observable is clear from the type.
Do I need to call Dispose on any of my subscriptions to
this chain, or is it safe enough to leave everything up to garbage
collection when the containing class goes out of scope?
The ChangeObservable.Subscribe at the end could live forever, preventing the object from being garbage collected if the event is subscribed to, though that could also be your intention. Operator subscriptions are generally fine. I can't see the code for your ChangedAsObservable like functions. If they don't include a Subscribe or an event subscription, they're probably fine as well.
Keep in mind,
I'm observing events from watcher, so there's some shared lifecycle
there.
Since FileWatcher implements IDisposable, you should probably use Observable.Using around it so you can combine the lifecycles.
Is it okay to take an observable and wire them into an event on
my own class (Changed in the example above), or is the idea to stay
out of the native .net event system and leak my IObservable?
I would prefer to stay in Rx. The problem with event subscriptions is that they generally live forever. You lose the ability to control subscription lifecycle. They're also feel so much more primitive. But again, that's a bit subjective.
I'm trying to understand the purpose of this library by Jake Warthon:
https://github.com/JakeWharton/RxRelay
Basically: A Subject except without the ability to call onComplete or
onError. Subjects are stateful in a damaging way: when they receive an
onComplete or onError they no longer become usable for moving data.
I get idea, it's a valid use case, but the above seems easy to achieve just using the existing subjects.
1. Don't forward errors/completions events to the subject:
`observable.subscribe({ subject.onNext(it) }, { log error / throw exception },{ ... })`
2. Don't expose the subject, make your method signature return an observable instead.
fun(): Observable<> { return subject }
I'm obviously missing something here and I'm very curios on what it is!
class MyPublishRelay<I> : Consumer<I> {
private val subject: Subject<I> = PublishSubject.create<I>()
override fun accept(intent: I) = subject.onNext(intent)
fun subscribe(): Disposable = subject.subscribe()
fun subscribe(c: Consumer<in I>): Disposable = subject.subscribe(c)
//.. OTHER SUBSCRIBE OVERLOADS
}
subscribe has overloads and, usually, people get used to the subscribe(Consumer) overload. Then they use subjects and suddenly onComplete is also invoked. RxRelay saves the user from themselves who don't think about the difference between subscribe(Consumer) and subscribe(Observer).
Don't forward errors/completions events to the subject:
Indeed, but based on our experience with beginners, they often don't think about this or even know about the available methods to consider.
Don't expose the subject, make your method signature return an observable instead.
If you need a way to send items into the subject, this doesn't work. The purpose is to use the subject to perform item multicasting, sometimes from another Observable. If you are in full control of the emissions through the Subject, you should have the decency of not calling onComplete and not letting anything else do it either.
Subjects have far more overhead because they have to track and handle
terminal event states. Relays are stateless aside from subscription
management.
- Jake Wharton
(This is from the issue OP opened on GitHub and felt it was a more a correct answer and wanted to "relay" it here for others to see. https://github.com/JakeWharton/RxRelay/issues/30)
In addition to #akarnokd answer:
In some cases you can't control the flow of data inside the Observable, an example of this is when observing data changes from a database table using Room Database.
If you use Subjects, executing subjects.getValue will always throw error about null safety. So you have to put "? or !!" everywhere in your code even though you know that it will be not nullable.
public T getValue() {
Object o = value.get();
if (NotificationLite.isComplete(o) || NotificationLite.isError(o)) {
return null;
}
return NotificationLite.getValue(o);
}
I have an Update method in my repository which I'm using to update articles on my project. I was initially using this method only to carry out admin edits for articles. It handles that correctly, but I decided I'd like to add a simple mechanism to calculate "most read" articles. In order to do that, I'd like to update TimesRead property each time an article has been viewed. This has been giving me trouble with the updates which seem to revolve around using ObjectStateManager.ChangeObjectState. Here's my Update method:
public void Update(Article article)
{
if (article == null) return;
db.Articles.Attach(article);
db.ObjectStateManager.ChangeObjectState(article, EntityState.Modified);
db.SaveChanges();
}
In my AdminController the following method updates correctly:
[HttpPost]
public ActionResult Edit(AdminEditViewModel viewModel)
{
if (ModelState.IsValid)
{
Article article = Mapper.Map<AdminEditViewModel, Article>(viewModel);
articleRepository.Update(article);
return RedirectToAction("Index");
}
viewModel.Categories = new SelectList(categoryRepository.GetAll(), "CategoryID", "Name", viewModel.CategoryID);
return View(viewModel);
}
However, in the TimesRead scenario, the update will trigger an exception of:
The object cannot be attached because it is already in the object context. An object can only be reattached when it is in an unchanged state.
Relevant code from that controller method:
var model = articleRepository.GetByID(id);
model.TimesRead++;
articleRepository.Update(model);
return View(model);
After having a look around to see what I can do to solve this, I came across the answer to this SO question. So I implemented that answer by replacing my Update method with the code suggested. This also works correctly in my admin scenario but not in the TimesRead scenario. The following exception is thrown:
An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.
The exceptions are quite clear in their meaning but it does leave me wondering how I am supposed to handle simple updates such as these. I found that I can "fool" the EF into thinking the model is unchanged by setting EntityState.Unchanged and that will update TimesRead but give an exception for admin updates, stating the ObjectStateManager doesn't hold a reference to the object.
It's also clear to me how these scenarios differ. The Edit action is mapping properties from a ViewModel onto a new, unattached Article object, whereas, ArticleController is dealing with an object retrieved directly from the context. That leaves me with the feeling I should refactor one of those controller methods so the steps taken to update are the same. I'm just not really sure how I should even approach that as both approaches seem like they should be able to coexist to me. So my question is, what can I change to get both types of update to work correctly?
Thanks for your time and I'm really sorry for the amount of code posted. I just feel it is all relevant to the problem.
The primary difference between your two methods is that the Admin Edit method creates a new Article from your AdminEditViewModel, then it attaches this newly created Article to your database. This works because it's a new object that has never been attached to a dc.
In the second case, you get an Article from the repository, update that Article, then try and attach it again, this fails because it's not a newly created Article, it's an Article returned from the db Context in the first place so it's already attached. and you are trying to attach it again.
Ive just started using EF4 with the repository pattern. Im having to call the dispose method after every use of context or wrap code arround in the using block. Can I use the ObjectContext without doing this in every method I write or is there a better way of handling this in the repository.
Also I dont want to pass the ObjectContext to the repository from the UI as well.
To do this as resource effectively as possible without dependency injection, I would suggest that you implement a private, lazy-loading property for the object context.
private ObjectContext _context;
private ObjectContext Context
{ get
{
return _context ?? (_context = new ObjectContext());
}
}
Next, make your repository implement IDisposable and take care of the object context in your dispose method:
public Repository : IDisposable
{
...
public void Dispose()
{
_context.Dispose();
}
}
Then, you just use the property in all your methods, and wrap usage of your repository in using statements.
To decrease traffic to the database, you could also factor out the saving to a separate method on the repository, which just forwards the call to the object context. That way you get more control of when data is saved in the UI layer, even though you don't control how. That means you could do
using (var repo = new Repository())
{
repo.AddSomeStuff("this", "is", true);
repo.ChangeSomethingElse("yes, please");
repo.Save();
}
and there would only be one call from EF to the database. On the other hand, if you do
using (var repo = new Repository())
{
repo.AddSomeStuff("this", "is", true);
repo.ChangeSomethingElse("yes, please");
}
nothing happens, which might be confusing.
The general pattern for using an object context is:
public BusinessObject GetSomething(){
using (MyObjectContext context = new MyObjectContext()){
//..do fun stuff
}
}
Which hopefully is the pattern you are using. Calling dispose seems a little overkill when you can just use a "using" statement.
Another option is if you are going to be doing multiple DB queries in a flow. I have seen a pattern where you can reuse the same context within the thread. People basically implement a Thread based singleton pattern and pass around the context. Advantages to this is not having to rebuild the context, as well as some in memory caching. Downside is you could run into concurrency issues. Someone updating something that you have cached internally in EF.
I am guessing the second case doesn't really apply because it sounds like you are writting a small app. (that statement was based on your comments about passing a context from UI...a statement which will scare any good code architect).
If you are interested in a thread based singleton. First learn about the Singleton pattern, and then check out this blog about "DataContext" threads. You will have to change the "DataContext" type to the ObjectContext class but it would work.
EDIT
I will say I overlooked an obvious solution and that would be the below ;). Just using a property based Object Context and playing your repository in a using statement. It would be the same as the using example above, but you would implement IDisoposable.