Lazy Using block #760
Replies: 10 comments
-
Can't you solve this by creating a Usage would look like this: using (var pushService = LazyDisposable.Create(() => new WebPushService(someContext)))
{
if (CompanyID != null)
{
pushService.Value.PushRefresh("email-refresh-" + CompanyID);
}
if (ParentEmailID != null)
{
pushService.Value.PushRefresh("parent-email-" + ParentEmailID);
}
if (ProjectID != null)
{
pushService.Value.PushRefresh("project-" + ProjectID);
}
} Possible implementation: public class LazyDisposable<T> : IDisposable where T : IDisposable
{
private Lazy<T> lazy;
public LazyDisposable(Func<T> valueFactory) => lazy = new Lazy<T>(valueFactory);
public T Value => lazy.Value;
public void Dispose()
{
if (lazy.IsValueCreated)
lazy.Value.Dispose();
// TODO: ensure lazy is unusable after Dispose is called
}
}
public static class LazyDisposable
{
public static LazyDisposable<T> Create<T>(Func<T> valueFactory) where T : IDisposable
=> new LazyDisposable<T>(valueFactory);
} |
Beta Was this translation helpful? Give feedback.
-
I am currently using,
I don't want to really use any heap if possible, something at compiler level would be nice which will generate code to avoid heap. Even in this case, there is an extra reference passed through heap for factory. |
Beta Was this translation helpful? Give feedback.
-
A lockless implementation is not coming to mind, but this should handle the race condition in @svick's TODO: public sealed class LazyDisposable<T> : IDisposable where T : IDisposable
{
private Lazy<T> lazy;
private readonly object lockObj = new object();
public LazyDisposable(Func<T> valueFactory) => lazy = new Lazy<T>(valueFactory);
public T Value
{
get
{
lock (lockObj)
{
if (lazy == null) throw new ObjectDisposedException(nameof(LazyDisposable<IDisposable>));
return lazy.Value;
}
}
}
public void Dispose()
{
lock (lockObj)
{
if (lazy.IsValueCreated)
lazy.Value.Dispose();
lazy = null;
}
}
} Of course then what's the point of using |
Beta Was this translation helpful? Give feedback.
-
Hmm, is this watertight? public sealed class LazyDisposable<T> : IDisposable where T : IDisposable
{
private Lazy<T> lazy;
public LazyDisposable(Func<T> valueFactory) => lazy = new Lazy<T>(valueFactory);
public T Value
{
get
{
var undisposed = Volatile.Read(ref lazy);
if (undisposed == null) throw new ObjectDisposedException(nameof(LazyDisposable<IDisposable>));
var value = undisposed.Value;
if (Volatile.Read(ref lazy) == null)
{
// If we are here, this means we've interleaved with Dispose:
// Value.get: undisposed = Volatile.Read(ref lazy);
// Dispose: undisposed = Interlocked.Exchange(ref lazy, null);
// Dispose: undisposed.IsValueCreated (false, exits)
// Value.get: undisposed.Value;
value.Dispose();
throw new ObjectDisposedException(nameof(LazyDisposable<IDisposable>));
}
return value;
}
}
public void Dispose()
{
var undisposed = Interlocked.Exchange(ref lazy, null);
if (undisposed == null) return;
if (undisposed.IsValueCreated)
undisposed.Value.Dispose();
}
} |
Beta Was this translation helpful? Give feedback.
-
Anybody that hates |
Beta Was this translation helpful? Give feedback.
-
That issue wouldn't change the current behavior. It would only allow for you to use |
Beta Was this translation helpful? Give feedback.
-
@HaloFour maybe I wasn't clear, but that's precisely what I want. |
Beta Was this translation helpful? Give feedback.
-
Oh sorry, I read that to mean that you were annoyed that the generic type argument wasn't a part of the name. You're right, if the goal is to produce "LazyDisposable" then having to supply the generic type argument is a bit obnoxious. |
Beta Was this translation helpful? Give feedback.
-
@jnm2 For the record, I didn't mean for the class to be thread-safe (most classes aren't) and the TODO was just "I'm too lazy to properly implement error handling and it would just distract from my point anyway". |
Beta Was this translation helpful? Give feedback.
-
Ah. |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Here is piece of code,
If there was some way around to write following...
It would defer creation of
WebPushService
until it is required first time, problem is, the code is executed 20% time, so there is no point in creatingWebPushService
always as opposed to only when needed. All push are queued until service is disposed and all pushes are sent somewhere.** Performance **
This issue focuses more towards performance, not just a syntactic sugar.
Lazy<T>
is unnecessarily heavy, also problem focuses in not allocating object at all if not required,Lazy<T>
on other hand uses more heap and more complex CPU operations to mange multithreading access.Beta Was this translation helpful? Give feedback.
All reactions