Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/275.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 允许添加、删除等子对象以及广播事件的接口最佳实践(类似于ObservableCollection)_C#_Design Patterns_Interface - Fatal编程技术网

C# 允许添加、删除等子对象以及广播事件的接口最佳实践(类似于ObservableCollection)

C# 允许添加、删除等子对象以及广播事件的接口最佳实践(类似于ObservableCollection),c#,design-patterns,interface,C#,Design Patterns,Interface,我正在尝试为文件夹指定接口。该接口应允许 -添加或删除IFile类型的文件 -获取IFile的列表 -每当添加/删除/更改文件时广播事件(例如,供GUI订阅) 我正在努力找到最好的方法。到目前为止,我提出了三个想法: 1. 公共接口IFolder\u v1 { 可观察收集文件; } 2. 公共接口IFolder\u v2 { 无效添加(IFile); 清除空洞(IFile); IEnumerable文件{get;} 事件处理程序已导入{get;} EventHandler OnFileRemo

我正在尝试为文件夹指定接口。该接口应允许 -添加或删除IFile类型的文件 -获取IFile的列表 -每当添加/删除/更改文件时广播事件(例如,供GUI订阅)

我正在努力找到最好的方法。到目前为止,我提出了三个想法:

1.
公共接口IFolder\u v1
{
可观察收集文件;
}
2.
公共接口IFolder\u v2
{
无效添加(IFile);
清除空洞(IFile);
IEnumerable文件{get;}
事件处理程序已导入{get;}
EventHandler OnFileRemoved{get;}
EventHandler OnFileDeleted{get;}
}
3.
公共接口IFolder\u v3
{
无效添加(IFile);
清除空洞(IFile);
IEnumerable文件{get;}
EventHandler onFileChanged{get;}
}
公共类CRUD_EventArgs:EventArgs
{
公共枚举操作
{
补充,
远离的,
更新
}
私人业务(op);
公共积垢事件参数(操作)
{
这是操作;
}
公共行动
{
得到
{
把这个还给我;
}
}
}
Idea#1的实现似乎非常好,因为它不需要太多代码,但存在一些问题:例如,如果IFolder的实现只允许添加特定类型的文件(例如,文本文件),并且在添加另一个文件时抛出异常,会怎么样?我认为用一个简单的可观察的收集方法是不可行的

Idea#2似乎还可以,但需要更多的代码。另外,定义三个单独的事件似乎有点乏味——如果一个对象需要订阅所有事件怎么办?为此,我们需要订阅3个不同的EventHandler。看起来很烦人。 与解决方案#1相比,使用起来也不那么简单。现在,需要调用.Add来添加文件,但文件列表存储在.files等中-因此命名约定比将所有内容捆绑在一个简单的子对象(.idea#1中的文件)中要不那么清晰

Idea#3绕过了所有这些问题,但拥有最长的代码。此外,我还必须使用一个定制的EventArgs类,我无法想象它在接口定义中是特别干净的?(为简单的CRUD事件通知定义这样的类似乎也太过分了,难道不应该存在某种类型的现有类吗?)


如果您能提供一些您认为最好的解决方案的反馈,我将不胜感激(甚至可能是我根本没有想到的)。有什么最佳实践吗?

请看一下框架的功能。它几乎满足了您的需要,但是如果您仍然需要实现自己的类,您可以通过查看它的实现方式(这与您的#2方法类似)来获取想法


话虽如此,我个人认为#3也是一种非常有效的方法。如果结果比较短的代码更具可读性和可维护性,那么不要害怕编写较长的代码(当然要在合理的范围内)。

我个人认为#2

在#1中,您只需公开整个对象集合,允许每个人对其执行任何操作


#3对我来说似乎不那么不言自明。虽然-我喜欢在编码时保持简单,所以我可能会有偏见。

如果观察者的寿命比被观察的东西短,我会避免事件。
observateCollection
举例说明的模式是一种更好的方法,其中集合为订阅的观察者提供一个可用于取消订阅的
IDisposable
对象。如果您使用这样的模式,您可以让您的类持有对订阅对象的弱引用(可能使用“长”弱引用),这将反过来持有对订阅者和识别订阅者的弱引用的强引用(可能是委托)。因此,废弃的订阅将被垃圾收集器清除;订阅者有责任确保存在对订阅对象的强根引用

除了可以清理废弃的订阅之外,使用
“一次性订阅对象”的方法是,取消订阅可以轻松实现无锁和线程安全,并在固定时间内运行。要处理订阅,只需清空其中包含的委托。如果每次尝试添加订阅都会导致订阅管理器检查两个订阅以确保它们仍然有效,则存在的订阅总数将永远不会增长到上次垃圾回收时有效订阅数的两倍以上。

各位,感谢您的输入。似乎在这个问题上意见分歧,所有的解决方案都是可以接受的,有一定的利弊。现在,我决定将ObservableCollection扩展到在集合发生任何更改之前(例如,在添加、删除项目之前)触发事件,并允许订阅者取消这些事件。这样,我可以使用这个类,并允许通过订阅事件并取消它们来实现某些验证逻辑,例如,如果尝试添加无效项。
public interface IFolder_v1
{
    ObservableCollection<IFile> files;
}
public interface IFolder_v2
{
    void add(IFile);
    void remove(IFile);
    IEnumerable<IFile> files { get; }

    EventHandler OnFileAdded { get; }
    EventHandler OnFileRemoved { get; }
    EventHandler OnFileDeleted { get; }
}
public interface IFolder_v3
{
    void add(IFile);
    void remove(IFile);
    IEnumerable<IFile> files { get; }

    EventHandler<CRUD_EventArgs> OnFilesChanged { get; }
}

public class CRUD_EventArgs : EventArgs
{
    public enum Operations
    {
        added,
        removed,
        updated
    }

    private Operations _op;

    public CRUD_EventArgs(Operations operation)
    {
        this._op = operation;
    }

    public  Operations operation
    {
        get
        {
            return this._op;
        }
    }
}