我有一个类来处理来自WinForms控件的事件.根据用户正在做的事情,我正在引用该类的一个实例并创建一个新实例来处理同一事件.我需要先从事件中取消订阅旧实例 - 这很容易.如果可能的话,我想以非专有方式这样做,看起来这是IDisposable的工作.但是,大多数文档仅在使用非托管资源时才建议使用IDisposable,这在此处不适用.
如果我实现IDisposable并取消订阅Dispose()中的事件,我是否会歪曲它的意图?我应该提供一个Unsubscribe()函数并调用它吗?
编辑:这是一些虚拟代码,它显示了我正在做的事情(使用IDisposable).我的实际实现与一些专有数据绑定(长篇故事)有关.
class EventListener : IDisposable
{
private TextBox m_textBox;
public EventListener(TextBox textBox)
{
m_textBox = textBox;
textBox.TextChanged += new EventHandler(textBox_TextChanged);
}
void textBox_TextChanged(object sender, EventArgs e)
{
// do something
}
public void Dispose()
{
m_textBox.TextChanged -= new EventHandler(textBox_TextChanged);
}
}
class MyClass
{
EventListener m_eventListener = null;
TextBox m_textBox = new TextBox();
void SetEventListener()
{
if (m_eventListener != null) m_eventListener.Dispose();
m_eventListener = new EventListener(m_textBox);
}
}
Run Code Online (Sandbox Code Playgroud)
在实际代码中,"EventListener"类涉及更多,每个实例都具有独特的重要性.我在集合中使用它们,并在用户点击时创建/销毁它们.
结论
我接受gbjbaanb的回答,至少目前如此.我觉得使用熟悉的界面的好处超过了在没有涉及非托管代码的情况下使用它的任何可能的缺点(这个对象的用户怎么会知道?).
如果有人不同意 - 请发帖/评论/编辑.如果可以对IDisposable做出更好的论证,那么我将改变接受的答案.
我有3个关于事件的问题:
我有这样的代码:
Ctor:目的:用于数据库属性更新
this.PropertyChanged += (o, e) =>
{
switch (e.PropertyName)
{
case "FirstName": break;
case "LastName": break;
}
};
Run Code Online (Sandbox Code Playgroud)
这个:目的:用于GUI绑定将模型包装到视图模型中
ObservableCollection<Period> periods = _lpRepo.GetDailyLessonPlanner(data.DailyDate);
PeriodListViewModel = new ObservableCollection<PeriodViewModel>();
foreach (Period period in periods)
{
PeriodViewModel periodViewModel = new PeriodViewModel(period,_lpRepo);
foreach (DocumentListViewModel documentListViewModel in periodViewModel.DocumentViewModelList)
{
documentListViewModel.DeleteDocumentDelegate += new Action<List<Document>>(OnDeleteDocument);
documentListViewModel.AddDocumentDelegate += new Action(OnAddDocument);
documentListViewModel.OpenDocumentDelegate += new Action<int, string>(OnOpenDocument);
}
PeriodListViewModel.Add(periodViewModel);
}
Run Code Online (Sandbox Code Playgroud) 我的一位同事问我是否需要取消订阅对话框的 afterClosed() Observable。
我们使用 takeUntil 模式取消订阅 ngOnDestroy() 上的所有 Observable。
this.backEvent = fromEvent(window, 'popstate')
.pipe(
takeUntil(this.destroy$)
)
.subscribe(
() => {
this.navigationService.backClicked = true;
this.navigationService.navigateBackToDirectoryCenter();
}
);
Run Code Online (Sandbox Code Playgroud)
ngOnDestroy()
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
Run Code Online (Sandbox Code Playgroud)
那么是否有必要取消订阅 afterClosed() Observable 呢?
dialogRef.afterClosed().subscribe(
(data) => {
console.log(data);
}
},
);
Run Code Online (Sandbox Code Playgroud)
或者?
dialogRef.afterClosed()
.pipe(
takeUntil(this.destroy$)
)
.subscribe(
(data) => {
console.log(data);
},
);
Run Code Online (Sandbox Code Playgroud) 从http订阅中取消订阅Angular2服务的最佳做法是什么?
目前我这样做,但我不确定这是否是最好的方式.
import { Injectable } from "@angular/core";
import { Http } from "@angular/http";
import { Subject } from "rxjs/Subject";
import { ISubscription } from "rxjs/Subscription";
@Injectable()
export class SearchService {
private _searchSource = new Subject<any>();
public search$ = this._searchSource.asObservable();
constructor(private _http: Http) {}
public search(value: string) {
let sub: ISubscription = this._http.get("/api/search?value=" + value)
.map(response => <any>response.json())
.do(data => this._searchSource.next(data))
.finally(() => sub.unsubscribe()).subscribe();
}
}
Run Code Online (Sandbox Code Playgroud) 在Gmail中,如果您收到来自新闻列表的电子邮件,则会在电子邮件地址旁边显示"取消订阅"链接,如下所示:
Google+ <noreply-67e4f7ae@plus.google.com> Unsubscribe
Run Code Online (Sandbox Code Playgroud)
标题名称List-Unsubscribe:标识了网址或电子邮件.
在Gmail中,我可以看到电子邮件原件以查看标题:
Received-SPF: pass (google.com: domain of root@domain.net designates 123.123.123.123 as permitted sender) client-ip=123.123.123.123;
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of root@domain.net designates 123.123.123.123 as permitted sender) smtp.mail=root@domain.net;
dkim=pass header.i=@domain.com
List-Unsubscribe: <http://domain.com/uns.html?test=wdqwqw>
Run Code Online (Sandbox Code Playgroud)
我有List-Unsubscribe标题集,spf和dkim验证通过.
有什么不对?为什么gmail没有显示取消订阅链接?
我正在制作一个拖放应用程序,我创建了一个可观察鼠标位置,重新定位我的drag-object.
mouseMove$: any;
constructor(){
this.mouseMove$ = Observable.fromEvent(document, 'mousemove')
.do((mouseevent: MouseEvent) => {
if (document.getElementById("drag-object")){
document.getElementById("drag-object").style.left = (mouseevent.clientX) + 'px';
document.getElementById("drag-object").style.top = (mouseevent.clientY) + 'px';
}
});
Run Code Online (Sandbox Code Playgroud)
通过这种实现,我可以通过这种方式订阅:
this.mouseMove$.subscribe();
Run Code Online (Sandbox Code Playgroud)
但我似乎无法取消订阅:
this.mouseMove$.unsubscribe();
Run Code Online (Sandbox Code Playgroud)
要么
this.mouseMove$.dispose();
Run Code Online (Sandbox Code Playgroud)
在任何一种情况下,我都会收到以下类型的错误:
TypeError:this.mouseMove $ .unsubscribe不是函数...
我不知道这是否与该做mouseMove$的类型any,但设置的类型,Observable并Observable<MouseEvent>没有工作.我在这里不理解什么?
有几种方法可以取消订阅 Angular 组件上的 observables(通过使用 ngOnDestroy)。应首选以下哪个选项?为什么(例如技术原因、性能等)?
使用 RxJS takeUntil 取消订阅
@Component({
selector: "app-flights",
templateUrl: "./flights.component.html"
})
export class FlightsComponent implements OnDestroy, OnInit {
private readonly destroy$ = new Subject();
public flights: FlightModel[];
constructor(private readonly flightService: FlightService) {}
ngOnInit() {
this.flightService
.getAll()
.pipe(takeUntil(this.destroy$))
.subscribe(flights => (this.flights = flights));
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
Run Code Online (Sandbox Code Playgroud)
显式调用 .unsubscribe(),例如通过使用单独的订阅实例
@Component({
selector: "app-flights",
templateUrl: "./flights.component.html"
})
export class FlightsComponent implements OnDestroy, OnInit {
private readonly subscriptions = new Subscription();
public flights: …Run Code Online (Sandbox Code Playgroud) 我想在我的服务发送的电子邮件的页脚中提供一个单击“取消订阅”链接。
显然,许多垃圾邮件扫描程序会扫描电子邮件,并会按照电子邮件中的任何链接扫描其内容中的恶意软件。到目前为止我使用的解决方法:
这样,用户通常只需要单击表单,他们就会收到“您已取消订阅”的消息。如果他们禁用了 JS,他们仍然可以手动提交确认表。
现在的问题是,像Office365的ATP这样的扫描器会打开页面,并在其中执行JS。通过执行 JS,他们提交表单并导致用户自动取消订阅。
我已经考虑向自动提交 JS 逻辑添加检查:
但这些似乎都是脆弱的方法,充其量是黑客攻击,随着电子邮件扫描仪改变他们的策略,这些方法必然会被破坏。
我相信这个问题在我之前有很多人。除了放弃单击功能之外,是否有已知的合理解决方法?
附注。我已经添加了对RFC 8058 的支持,但用户仍然会点击页脚中的链接。
我在想我在unsubscribe链接中创建一个停用代码及其用户ID.然后,当我的时事通讯的收件人点击该链接时,我可以查找他们的用户ID并查看停用代码是否匹配.
这听起来像是最好的方式吗?
还有什么其他方法?
我有以下课程:
public class Terminal : IDisposable
{
readonly List<IListener> _listeners;
public Terminal(IEnumerable<IListener> listeners)
{
_listeners = new List<IListener>(listeners);
}
public void Subscribe(ref Action<string> source)
{
source += Broadcast;
//Store the reference somehow?
}
void Broadcast(string message)
{
foreach (var listener in _listeners) listener.Listen(message);
}
public void Dispose()
{
//Unsubscribe from all the stored sources?
}
}
Run Code Online (Sandbox Code Playgroud)
我已经搜索了一段时间,似乎无法存储使用ref关键字传递的参数.尝试将源参数添加到列表或将其分配给字段变量不允许它保持对实际委托的原始引用的引用; 所以我的问题是:
谢谢.
编辑:似乎没有使用包装器或反射,没有解决给定的问题.我的目的是使类尽可能地可移植,而不必将代理包装在辅助类中.谢谢大家的贡献.
unsubscribe ×10
angular ×4
email ×3
c# ×2
events ×2
observable ×2
rxjs ×2
.net ×1
delegates ×1
gmail ×1
idisposable ×1
newsletter ×1
office365 ×1
parameters ×1
ref ×1
rxjs5 ×1
spam ×1
subscribe ×1
typescript ×1