【发布时间】:2022-10-08 00:42:48
【问题描述】:
所以我发现自己需要对一些 Blazor 组件进行子类化,其中一个原因是我需要从本质上创建一个装饰器来扩展它的功能。该扩展的一部分是附加一些额外的事件处理。由于组件现在使用EventCallback,它不是委托类型,因此我不能像使用多播委托那样简单地向它添加另一个处理程序。我可以替换它,但这意味着该组件的任何消费者都无法注册他们自己的任何处理程序,因为我的会覆盖它,所以现在我正在尝试包装它。这是场景的伪表示以及我正在尝试做的事情
public class OriginalBlazorComponent : ComponentBase
{
[Parameter]
public EventCallback<int> SomethingChanged { get; set; }
private async Task SomeInternalProcess()
{
// ... some work here
await SomethingChanged.InvokeAsync(1);
}
}
public class MySubclassedComponent : OriginalBlazorComponent
{
public override async Task SetParametersAsync(ParameterView parameters)
{
// I want to combine anything that the user may have registered with my own handling
SomethingChanged = EventCallback.Factory.Create(this, async (int i) =>
{
// this causes a stack overflow because i just replaced it with this callback
// so it's essentially calling itself by this point.
await SomethingChanged.InvokeAsync(i);
await DoMyOwnStuff(i);
});
await base.SetParametersAsync(this);
}
}
这里的想法是,我只是通过在SetParametersAsync() 中解决这个问题来确保用户的处理程序已被绑定,以便我可以将它包装在一个新的回调中,该回调将首先调用他们的处理程序,然后再运行我的处理程序。但是由于它是具有由基类调用的属性的基组件,这意味着我需要用我的新处理程序替换该特定属性,但这样做,这意味着新处理程序正在调用实际上是旧处理程序现在是新的处理程序,所以它现在是一个无限递归调用堆栈,并导致堆栈溢出。
所以我的第一个想法是,如果我能以某种方式获得原始 EventCallback 的副本,或者至少提取它的委托以便我可以创建一个新的回调,那么它就不会再引用自己了(因为它是一个结构而感到困惑,我想它总是自然地是副本),但我找不到任何方法来做到这一点。我尝试只使用EventCallback.Factory.Create(this, SomethingChanged),希望它会使用相同的委托创建一个全新的回调实例,但它没有改变任何东西;同样的结果。
如果我可以覆盖原始组件的 SomeInternalProcess() 方法,这样我就可以在调用基本方法之前或之后将我的进程插入到那里,这当然不是问题,但它是第 3 方库。或者,如果 SomethingChanged 属性本身是虚拟的,我可以覆盖它以拦截它的设置器,但事实并非如此。
所以简而言之,有没有办法实现与多播委托相同的效果,以便我可以保留任何已注册的处理程序但与我自己的结合?或者至少有某种方式取消引用原始的 EventCallback 或提取它的委托,以便我可以创建一个新的委托?
例如
// how do I acheive something akin to
SomethingChanged += MyDelegate;
更新1:
我尝试通过在子类上声明我自己的来“隐藏”SomethingChanged 事件回调,以便我可以在基础上注册我自己的处理程序,其中除了我自己的处理程序之外还包括用户的处理程序。这在标准 C# 测试中有效,但 Blazor 不喜欢它。它在渲染期间将其视为重复属性并引发异常。
更新 2:
哈卡罗尼。 EventCallback 和 EventCallback<T> 都将委托存储在名为 Delegate 的内部字段中。为了看看它是否可以工作,我通过反射将它取出并使用它来创建一个新的 EventCallback 来替换用户创建的 EventCallback,它将我们两个包裹在一起,先执行他们的然后我的。它有效,而且我还没有看到任何奇怪的副作用。但我讨厌它,原因很明显。但这让我想知道,也许我所需要的只是让微软公开那个领域。我敢肯定它存在某种风险,但它只是一个函数指针。只要它是只读的,应该没问题吧?
【问题讨论】:
-
我将通过在我的子类中声明我自己来尝试简单地隐藏“SomethingChanged”。因此,我会将我的处理程序添加到基础,然后在我的处理程序中,我将调用客户端处理程序,因为它们应该是分开的。感觉。所以。错误的。尽管....
-
Welp 在标准 c# 中有效,但 Blazor 不喜欢它,因为它将其视为重复属性并抛出。
-
除了
OriginalBlazorComponent实例的父组件之外,还有谁在尝试使用SomethingChanged?如何? -
@MrCakaShaunCurtis 设计为“未知”。它是一个组件,你不知道谁会使用它。据您所知,它可能是世界上任何其他开发人员。原始组件的设计公开了该事件回调,因此该控件的用户可以订阅并使用它做任何他们想做的事情(例如,当某些内容更改选项卡索引时,我还想更新此值以便其他控件可以做出反应)。我只需要在其中插入一些其他东西,而不会破坏他们仍然使用该界面的能力。
-
请参阅我更新的答案以及对您的答案的一些修改。
标签: .net-core blazor multicastdelegate