/* ----------------------------------------------------------------- */ /// /// NtpClient /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /* ----------------------------------------------------------------- */ public NtpClient(string server, int port) { Timeout = TimeSpan.FromSeconds(5); Host = Dns.GetHostEntry(server); Port = port; _dispose = new OnceAction <bool>(Dispose); }
/* ----------------------------------------------------------------- */ /// /// MainFacade /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="src">設定用オブジェクト</param> /// <param name="context">同期用オブジェクト</param> /// /* ----------------------------------------------------------------- */ public MainFacade(SettingsFolder src, SynchronizationContext context) { _dispose = new OnceAction<bool>(Dispose); src.LoadOrDefault(new LocalSettings()); this.LogInfo($"Owner:{src.Lock.UserName}@{src.Lock.MachineName} ({src.Lock.Sid})"); this.LogInfo($"User-Agent:{src.UserAgent}"); Settings = src; Settings.PropertyChanged += WhenSettingsChanged; Settings.AutoSave = true; var feeds = Settings.IO.Combine(Settings.DataDirectory, LocalSettings.FeedFileName); var cache = Settings.IO.Combine(Settings.DataDirectory, LocalSettings.CacheDirectoryName); _core = new RssSubscriber(context) { IO = Settings.IO, FileName = feeds, CacheDirectory = cache, Capacity = Settings.Shared.Capacity, IsReadOnly = Settings.Lock.IsReadOnly, UserAgent = Settings.UserAgent }; _core.Set(RssCheckFrequency.High, Settings.Shared.HighInterval); _core.Set(RssCheckFrequency.Low, Settings.Shared.LowInterval); _core.Received += WhenReceived; _checker = new UpdateChecker(Settings); Data = new MainBindableData(_core, Settings, context); }
/* ----------------------------------------------------------------- */ /// /// RssSubscriber /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="context">同期用オブジェクト</param> /// /* ----------------------------------------------------------------- */ public RssSubscriber(SynchronizationContext context) { _dispose = new OnceAction <bool>(Dispose); _context = context; _tree = new BindableCollection <IRssEntry> { Context = context }; _tree.CollectionChanged += (s, e) => { AutoSaveCore(); CollectionChanged?.Invoke(this, e); }; _monitors[0] = new RssMonitor { Interval = TimeSpan.FromHours(1) }; _monitors[0].Subscribe(e => Received?.Invoke(this, ValueEventArgs.Create(e))); _monitors[1] = new RssMonitor { Interval = TimeSpan.FromHours(24) }; _monitors[1].Subscribe(e => Received?.Invoke(this, ValueEventArgs.Create(e))); _monitors[2] = new RssMonitor(); // for RssCheckFrequency.None _monitors[2].Subscribe(e => Received?.Invoke(this, ValueEventArgs.Create(e))); _autosaver.AutoReset = false; _autosaver.Interval = 1000.0; _autosaver.Elapsed += WhenAutoSaved; }
/* ----------------------------------------------------------------- */ /// /// BindableCollection /// /// <summary> /// Initializes a new instance of the <c>BindableCollection</c> /// class with the specified collection. /// </summary> /// /// <param name="collection">Collection to be copied.</param> /// <param name="dispatcher">Dispatcher object.</param> /// /* ----------------------------------------------------------------- */ public BindableCollection(IEnumerable <T> collection, IDispatcher dispatcher) : base(collection ?? Enumerable.Empty <T>()) { _dispose = new OnceAction <bool>(Dispose); Dispatcher = dispatcher; SetHandler(this); }
/* ----------------------------------------------------------------- */ /// /// SizeHacker /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /* ----------------------------------------------------------------- */ public SizeHacker(Control control, int grip) { SizeGrip = grip; Root = control; _dispose = new OnceAction <bool>(Dispose); StartMonitor(Root); }
/// <summary> /// Load/Clear each class and session only once. /// </summary> /// <param name="action">Load or Clear</param> /// <param name="storageID">Class identifier (there can be multiple /// persistent classes to load on a page)</param> /// <returns>true when called the first time for that storageID, false afterwards</returns> private static bool Once(OnceAction action, string storageID) { var onceKey = RequestQuerySessionMiddleware.SessionOnceKey(action); HashSet <string> done; bool isDone; if (HttpContext.Session.TryGetValue(onceKey, out byte[] bytes))
public ModelViewer(ITagContainer diContainer) { this.diContainer = diContainer; device = diContainer.GetTag <GraphicsDevice>(); resourcePool = diContainer.GetTag <IResourcePool>(); textureLoader = diContainer.GetTag <IAssetLoader <Texture> >(); Window = diContainer.GetTag <WindowContainer>().NewWindow("Model Viewer"); Window.InitialBounds = new Rect(float.NaN, float.NaN, 1100.0f, 600.0f); Window.AddTag(this); editor = new TwoColumnEditorTag(Window, diContainer); var onceAction = new OnceAction(); Window.AddTag(onceAction); Window.OnContent += onceAction.Invoke; var menuBar = new MenuBarWindowTag(Window); menuBar.AddButton("Open", HandleMenuOpen); fbArea = Window.GetTag <FramebufferArea>(); fbArea.OnResize += HandleResize; fbArea.OnRender += HandleRender; modelMaterialEdit = new ModelMaterialEdit(Window, diContainer); diContainer.GetTag <OpenDocumentSet>().AddEditor(this); openFileModal = new OpenFileModal(diContainer); openFileModal.Filter = "*.dff"; openFileModal.IsFilterChangeable = false; openFileModal.OnOpenedResource += Load; imGuiRenderer = Window.Container.ImGuiRenderer; locationBuffer = new LocationBuffer(device); AddDisposable(locationBuffer); var localDiContainer = diContainer.ExtendedWith(locationBuffer); camera = new Camera(localDiContainer); AddDisposable(camera); controls = new OrbitControlsTag(Window, camera.Location, localDiContainer); AddDisposable(controls); gridRenderer = new DebugGridRenderer(diContainer); gridRenderer.Material.LinkTransformsTo(camera); gridRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(gridRenderer); triangleRenderer = new DebugTriangleLineRenderer(diContainer); triangleRenderer.Material.LinkTransformsTo(camera); triangleRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(triangleRenderer); planeRenderer = new DebugPlaneRenderer(diContainer); planeRenderer.Material.LinkTransformsTo(camera); planeRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(planeRenderer); editor.AddInfoSection("Statistics", HandleStatisticsContent); editor.AddInfoSection("Materials", HandleMaterialsContent); editor.AddInfoSection("Skeleton", HandleSkeletonContent); editor.AddInfoSection("Collision", HandleCollisionContent); }
/* ----------------------------------------------------------------- */ /// /// PresenterBase /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="view">View オブジェクト</param> /// <param name="events">EventHub オブジェクト</param> /// <param name="context">同期コンテキスト</param> /// /* ----------------------------------------------------------------- */ public PresenterBase(TView view, IEventHub events, SynchronizationContext context) { _dispose = new OnceAction <bool>(Dispose); View = view; EventHub = events; SynchronizationContext = context; }
/* ----------------------------------------------------------------- */ /// /// ImageEntry /// /// <summary> /// Initializes a new instance of the ImageItem class with the /// specified arguments. /// </summary> /// /// <param name="image">Delegation to get an image.</param> /// <param name="selection">Shared object for selection.</param> /// <param name="preferences">Image preferences.</param> /// /* ----------------------------------------------------------------- */ public ImageItem(Func <ImageItem, ImageSource> image, ImageSelection selection, ImagePreferences preferences) { _dispose = new OnceAction <bool>(Dispose); _image = image; _selection = selection; _preferences = preferences; _preferences.PropertyChanged += WhenPreferencesChanged; }
/* ----------------------------------------------------------------- */ /// /// FileTransfer /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="format">変換形式</param> /// <param name="dest">最終的な保存パス</param> /// <param name="work">作業ディレクトリ</param> /// <param name="io">I/O オブジェクト</param> /// /* ----------------------------------------------------------------- */ public FileTransfer(Format format, string dest, string work, IO io) { _dispose = new OnceAction <bool>(Dispose); IO = io; Format = format; Information = io.Get(dest); WorkDirectory = GetWorkDirectory(work); Value = IO.Combine(WorkDirectory, GetName()); }
/* ----------------------------------------------------------------- */ /// /// RssCategory /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="context">同期用コンテキスト</param> /// /* ----------------------------------------------------------------- */ public RssCategory(SynchronizationContext context) { _dispose = new OnceAction <bool>(Dispose); Context = context; Children = new BindableCollection <IRssEntry> { Context = context }; Children.CollectionChanged += WhenChildrenChanged; }
public void Invoke() { var dest = 0; var once = new OnceAction(() => dest++); var tasks = 5.Make(i => Task.Run(() => once.Invoke())); Task.WaitAll(tasks.ToArray()); Assert.That(once.Invoked, Is.True); Assert.That(dest, Is.EqualTo(1)); }
public void Invoke_Generics() { var src = "once"; var dest = ""; var once = new OnceAction <string>(s => dest += s); var tasks = 5.Make(i => Task.Run(() => once.Invoke(src))); Task.WaitAll(tasks.ToArray()); Assert.That(once.Invoked, Is.True); Assert.That(dest, Is.EqualTo(src)); }
/* ----------------------------------------------------------------- */ /// /// SevenZipLibrary /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /* ----------------------------------------------------------------- */ public SevenZipLibrary() { _dispose = new OnceAction <bool>(Dispose); var asm = Assembly.GetExecutingAssembly().GetReader(); var dir = Path.GetDirectoryName(asm.Location); _handle = Kernel32.NativeMethods.LoadLibrary(Path.Combine(dir, "7z.dll")); if (_handle.IsInvalid) { throw new Win32Exception("LoadLibrary"); } }
/* ----------------------------------------------------------------- */ /// /// ArchiveExtractCallback /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="src">圧縮ファイルのパス</param> /// <param name="dest">展開先ディレクトリ</param> /// <param name="items">展開項目一覧</param> /// <param name="io">ファイル操作用オブジェクト</param> /// /* ----------------------------------------------------------------- */ public ArchiveExtractCallback(string src, string dest, IEnumerable <ArchiveItem> items, IO io) : base(src, io) { _dispose = new OnceAction <bool>(Dispose); Destination = dest; Items = items; TotalCount = -1; TotalBytes = -1; Report.Count = 0; Report.Bytes = 0; _inner = Items.GetEnumerator(); }
/* ----------------------------------------------------------------- */ /// /// FileItem /// /// <summary> /// Initializes a new instance with the specified arguments. /// </summary> /// /// <param name="src">Path of the source file.</param> /// <param name="selection">Shared object for selection.</param> /// <param name="io">I/O handler.</param> /// /* ----------------------------------------------------------------- */ public FileItem(string src, Selection <FileItem> selection, IO io) { _dispose = new OnceAction <bool>(Dispose); _selection = selection; var info = io.Get(src); Name = info.Name; FullName = info.FullName; Length = info.Length; LastWriteTime = info.LastWriteTime; Icon = info.GetIcon(IconSize.Small).ToBitmap().ToBitmapImage(true); }
/* ----------------------------------------------------------------- */ /// /// MessengerClient /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="id">識別子</param> /// /* ----------------------------------------------------------------- */ public MessengerClient(string id) { var uri = new Uri($"net.pipe://localhost/{id}"); var address = new EndpointAddress(uri); var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); _dispose = new OnceAction <bool>(Dispose); _callback = new MessengerServiceCallback <TValue>(); _context = new InstanceContext(_callback); _factory = new DuplexChannelFactory <IMessengerService>(_callback, binding, address); Recreate(); }
/* ----------------------------------------------------------------- */ /// /// MessengerServer /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="id">識別子</param> /// /* ----------------------------------------------------------------- */ public MessengerServer(string id) { _dispose = new OnceAction <bool>(Dispose); var address = new Uri($"net.pipe://localhost/{id}"); var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.None); _service = new MessengerService <TValue>(); _host = new ServiceHost(_service); _host.AddServiceEndpoint(typeof(IMessengerService), binding, address); _host.Open(); }
public void Invoke(string obj) { var value = ""; var once = new OnceAction <string>(s => value += s); var tasks = new[] { Task.Run(() => once.Invoke(obj)), Task.Run(() => once.Invoke(obj)), Task.Run(() => once.Invoke(obj)), }; Task.WaitAll(tasks); Assert.That(value, Is.EqualTo(obj)); }
public void Invoke() { var value = 0; var once = new OnceAction(() => value++); var tasks = new[] { Task.Run(() => once.Invoke()), Task.Run(() => once.Invoke()), Task.Run(() => once.Invoke()), }; Task.WaitAll(tasks); Assert.That(value, Is.EqualTo(1)); }
public void Invoke_Twice() { var dest = 0; var once = new OnceAction(() => dest++) { IgnoreTwice = false }; var tasks = 5.Make(i => Task.Run(() => once.Invoke())); Assert.That(() => Task.WaitAll(tasks.ToArray()), Throws.TypeOf <AggregateException>().And.InnerException .TypeOf <TwiceException>()); Assert.That(dest, Is.EqualTo(1)); }
public ActorEditor(ITagContainer diContainer) { this.diContainer = diContainer; device = diContainer.GetTag <GraphicsDevice>(); resourcePool = diContainer.GetTag <IResourcePool>(); Window = diContainer.GetTag <WindowContainer>().NewWindow("Actor Editor"); Window.InitialBounds = new Rect(float.NaN, float.NaN, 1100.0f, 600.0f); Window.AddTag(this); editor = new TwoColumnEditorTag(Window, diContainer); var onceAction = new OnceAction(); Window.AddTag(onceAction); Window.OnContent += onceAction.Invoke; var menuBar = new MenuBarWindowTag(Window); menuBar.AddButton("Open", HandleMenuOpen); fbArea = Window.GetTag <FramebufferArea>(); fbArea.OnResize += HandleResize; fbArea.OnRender += HandleRender; diContainer.GetTag <OpenDocumentSet>().AddEditor(this); openFileModal = new OpenFileModal(diContainer); openFileModal.Filter = "*.aed"; openFileModal.IsFilterChangeable = false; openFileModal.OnOpenedResource += Load; locationBuffer = new LocationBuffer(device); AddDisposable(locationBuffer); localDiContainer = diContainer.ExtendedWith(locationBuffer); camera = new Camera(localDiContainer); AddDisposable(camera); controls = new OrbitControlsTag(Window, camera.Location, localDiContainer); AddDisposable(controls); localDiContainer.AddTag(camera); gridRenderer = new DebugGridRenderer(diContainer); gridRenderer.Material.LinkTransformsTo(camera); gridRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(gridRenderer); localDiContainer.AddTag <IStandardTransformMaterial>(gridRenderer.Material); editor.AddInfoSection("Info", HandleInfoContent); editor.AddInfoSection("Animation Playback", HandlePlaybackContent); editor.AddInfoSection("Body animations", () => HandlePartContent(false, () => body?.AnimationsContent() ?? false), false); editor.AddInfoSection("Wings animations", () => HandlePartContent(true, () => wings?.AnimationsContent() ?? false), false); editor.AddInfoSection("Body skeleton", () => HandlePartContent(false, () => body?.skeletonRenderer.Content() ?? false), false); editor.AddInfoSection("Wings skeleton", () => HandlePartContent(true, () => wings?.skeletonRenderer.Content() ?? false), false); editor.AddInfoSection("Head IK", HandleHeadIKContent, false); }
public EffectEditor(ITagContainer diContainer) { device = diContainer.GetTag <GraphicsDevice>(); resourcePool = diContainer.GetTag <IResourcePool>(); gameTime = diContainer.GetTag <GameTime>(); Window = diContainer.GetTag <WindowContainer>().NewWindow("Effect Editor"); Window.InitialBounds = new Rect(float.NaN, float.NaN, 1100f, 600f); Window.AddTag(this); editor = new TwoColumnEditorTag(Window, diContainer); var onceAction = new OnceAction(); Window.AddTag(onceAction); Window.OnContent += onceAction.Invoke; var menuBar = new MenuBarWindowTag(Window); menuBar.AddButton("Open", HandleMenuOpen); fbArea = Window.GetTag <FramebufferArea>(); fbArea.OnResize += HandleResize; fbArea.OnRender += HandleRender; diContainer.GetTag <OpenDocumentSet>().AddEditor(this); openFileModal = new OpenFileModal(diContainer) { Filter = "*.ed", IsFilterChangeable = false }; openFileModal.OnOpenedResource += Load; locationBuffer = new LocationBuffer(device); this.diContainer = diContainer.ExtendedWith(locationBuffer); AddDisposable(this.diContainer); this.diContainer.AddTag(camera = new Camera(this.diContainer)); this.diContainer.AddTag <IQuadMeshBuffer <EffectVertex> >(new DynamicQuadMeshBuffer <EffectVertex>(device.ResourceFactory, 1024)); this.diContainer.AddTag <IQuadMeshBuffer <SparkVertex> >(new DynamicQuadMeshBuffer <SparkVertex>(device.ResourceFactory, 256)); controls = new OrbitControlsTag(Window, camera.Location, this.diContainer); AddDisposable(controls); gridRenderer = new DebugGridRenderer(this.diContainer); gridRenderer.Material.LinkTransformsTo(camera); gridRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(gridRenderer); AddDisposable(textureLoader = new CachedAssetLoader <Texture>(new TextureAssetLoader(diContainer))); AddDisposable(clumpLoader = new CachedClumpAssetLoader(diContainer)); this.diContainer.AddTag <IAssetLoader <Texture> >(textureLoader); this.diContainer.AddTag <IAssetLoader <ClumpBuffers> >(clumpLoader); editor.AddInfoSection("Info", HandleInfoContent); editor.AddInfoSection("Playback", HandlePlaybackContent); }
/* ----------------------------------------------------------------- */ /// /// Messenger /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /// <param name="id">識別子</param> /// /* ----------------------------------------------------------------- */ public Messenger(string id) { _dispose = new OnceAction <bool>(Dispose); _mutex = new Mutex(false, id); IsServer = _mutex.WaitOne(0, false); if (IsServer) { _core = new MessengerServer <TValue>(id); } else { _core = new MessengerClient <TValue>(id); } }
public void Invoke_Generics_Twice() { var src = "twice"; var dest = ""; var once = new OnceAction <string>(s => dest += s) { IgnoreTwice = false }; var tasks = 5.Make(i => Task.Run(() => once.Invoke(src))); Assert.That(() => Task.WaitAll(tasks.ToArray()), Throws.TypeOf <AggregateException>().And.InnerException .TypeOf <TwiceException>()); Assert.That(dest, Is.EqualTo(src)); }
/* ----------------------------------------------------------------- */ /// /// Initialize /// /// <summary> /// オブジェクトを初期化します。 /// </summary> /// /* ----------------------------------------------------------------- */ private void Initialize(AssemblyReader reader, SettingsType type, string path) { Type = type; Path = path; Version = new SoftwareVersion(reader.Assembly); Company = reader.Company; Product = reader.Product; Value = new TValue(); Value.PropertyChanged += WhenChanged; _autosaver.AutoReset = false; _autosaver.Elapsed += WhenElapsed; _dispose = new OnceAction <bool>(Dispose); }
public SceneEditor(ITagContainer diContainer) { this.diContainer = diContainer; resourcePool = diContainer.GetTag <IResourcePool>(); Window = diContainer.GetTag <WindowContainer>().NewWindow("Scene Editor"); Window.AddTag(this); Window.InitialBounds = new Rect(float.NaN, float.NaN, 1100.0f, 600.0f); editor = new TwoColumnEditorTag(Window, diContainer); var onceAction = new OnceAction(); Window.AddTag(onceAction); Window.OnContent += onceAction.Invoke; locationBuffer = new LocationBuffer(diContainer.GetTag <GraphicsDevice>()); AddDisposable(locationBuffer); var menuBar = new MenuBarWindowTag(Window); menuBar.AddButton("Open", HandleMenuOpen); openFileModal = new OpenFileModal(diContainer); openFileModal.Filter = "*.scn"; openFileModal.IsFilterChangeable = false; openFileModal.OnOpenedResource += Load; camera = new Camera(diContainer.ExtendedWith(locationBuffer)); AddDisposable(camera); controls = new FlyControlsTag(Window, camera.Location, diContainer); gridRenderer = new DebugGridRenderer(diContainer); gridRenderer.Material.LinkTransformsTo(camera); gridRenderer.Material.World.Ref = Matrix4x4.Identity; AddDisposable(gridRenderer); fbArea = Window.GetTag <FramebufferArea>(); fbArea.OnResize += HandleResize; fbArea.OnRender += camera.Update; fbArea.OnRender += locationBuffer.Update; fbArea.OnRender += gridRenderer.Render; localDiContainer = diContainer .FallbackTo(Window) .ExtendedWith(this, Window, gridRenderer, locationBuffer) .AddTag <IAssetLoader <Texture> >(new CachedAssetLoader <Texture>(diContainer.GetTag <IAssetLoader <Texture> >())) .AddTag <IAssetLoader <ClumpBuffers> >(new CachedClumpAssetLoader(diContainer)) .AddTag(camera); new DatasetComponent(localDiContainer); new WorldComponent(localDiContainer); new ModelComponent(localDiContainer); new FOModelComponent(localDiContainer); new TriggerComponent(localDiContainer); new SelectionComponent(localDiContainer); }
public void Invoke_Twice() => Assert.That(() => { var dummy = 0; var once = new OnceAction(() => dummy++) { IgnoreTwice = false }; var tasks = new[] { Task.Run(() => once.Invoke()), Task.Run(() => once.Invoke()), Task.Run(() => once.Invoke()), }; Task.WaitAll(tasks); }, Throws.TypeOf <AggregateException>().And.InnerException.TypeOf <TwiceException>());
/* ----------------------------------------------------------------- */ /// /// ImageCollection /// /// <summary> /// Initializes a new instance of the ImageCollection class with /// the specified arguments. /// </summary> /// /// <param name="getter">Function to get the renderer.</param> /// <param name="context">Synchronization context.</param> /// /* ----------------------------------------------------------------- */ public ImageCollection(Func <string, IDocumentRenderer> getter, SynchronizationContext context) { ImageSource create(ImageItem e) => getter(e.RawObject.File.FullName).Create(e); void update(string s) { if (s == nameof(Preferences.VisibleLast)) { Reschedule(null); } }; _dispose = new OnceAction <bool>(Dispose); _inner = new ObservableCollection <ImageItem>(); _cache = new CacheCollection <ImageItem, ImageSource>(create); _inner.CollectionChanged += (s, e) => OnCollectionChanged(e); _cache.Created += (s, e) => e.Key.Refresh(); _cache.Failed += (s, e) => this.LogDebug($"[{e.Key.Index}] {e.Value.GetType().Name}"); Context = context; Selection = new ImageSelection { Context = context }; Preferences = new ImagePreferences { Context = context }; Create = (i, r) => { if (i < 0 || i >= Count) { return(null); } var src = _inner[i].RawObject; return(getter(src.File.FullName).Create(src, r)); }; Convert = (e) => Preferences.FrameOnly ? null : _cache.TryGetValue(e, out var dest) ? dest : Preferences.Dummy; Preferences.PropertyChanged += (s, e) => update(e.PropertyName); }
/* ----------------------------------------------------------------- */ /// /// DocumentWriterBase /// /// <summary> /// Initializes a new instance of the DocumentWriterBase class /// with the specified arguments. /// </summary> /// /// <param name="io">I/O handler.</param> /// /* ----------------------------------------------------------------- */ protected DocumentWriterBase(IO io) { _dispose = new OnceAction <bool>(Dispose); IO = io; }