反思仅在Blazor州管理部门的第一次呼叫中成功



我发现了一个奇怪的行为,我完全不知道它来自哪里,也不知道如何修复它。blazor状态管理(基于中介模式(出现了问题-库可以在这里找到:https://timewarpengineering.github.io/blazor-state/.

假设我们有以下枚举基类:

public abstract class Simple<TSimple> where TSimple: Simple<TSimple>
{
private readonly string _key;
protected Simple(string key)
{
_key = key;
}
public virtual string Key => _key;
public static TSimple Create(string key)
{
var obj = All.SingleOrDefault(e => e.Key == key);
return obj;
}
public static IReadOnlyCollection<TSimple> All => GetAll();
private static IReadOnlyCollection<TSimple> GetAll()
{
var enumerationType = typeof(TSimple);
return enumerationType.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy)
.Where(info => enumerationType.IsAssignableFrom(info.FieldType))
.Select(info => info.GetValue(null))
.Cast<TSimple>()
.ToArray();
}
}

以及以下枚举实现:

public class SimpleImpl : Simple<SimpleImpl>
{
public static readonly SimpleImpl One = new SimpleImpl("Important");
public static readonly SimpleImpl Two = new SimpleImpl("Urgent");
public static readonly SimpleImpl Three = new SimpleImpl("ImportantAndUrgent");
public static readonly SimpleImpl Four = new SimpleImpl("None");
private SimpleImpl(string key) : base(key)
{
}
}

到目前为止还不错。我在blazor应用程序中使用了这个枚举,在该应用程序中,通过gRPCWeb从后端检索数据,转换并添加到状态中。

因此,Index.chtml的代码部分看起来像这样:

@code
{
private AppState AppState => GetState<AppState>();
protected override async Task OnInitializedAsync()
{
foreach (var simple in new[] {"Important", "Urgent", "ImportantAndUrgent", "None"})
{
await Mediator.Send(new AppState.AddAction(simple));
}
}

这由处理程序处理:

public partial class AppState
{
public class AppHandler : ActionHandler<AddAction>
{
private AppState AppState => Store.GetState<AppState>();
public AppHandler(IStore store) : base(store)
{
}
public override async Task<Unit> Handle(AddAction aAction, CancellationToken aCancellationToken)
{
var simple = SimpleImpl.Create(aAction.Simple);
Console.WriteLine(simple == null); // First call false, afterwards true
AppState.Simples.Add(simple); // If I don't add the object to the state, Simple.Create always returns an object
return await Unit.Task;
}
}
}

这就是问题所在。在第一次尝试时,一切都正常,但如果函数被第二次调用(因此我的gRPC客户端返回多个项(,simple将始终为null。如果我移除AppState.Simples.Add(simple),那么它会再次工作。如果我在第一次运行时添加以下代码:Console.WriteLine(string.Join(",", SimpleImpl.All.Select(s => s.Key));,它会打印所有可能的值:

重要,紧急,重要和紧急,无

在第二次运行时,这是:

,紧急,,

Urgent在第一次运行时位于Dto中。因此,这似乎与List中的引用是如何保持活动的有关(这不应干扰Simple中的反射部分的工作方式(。

此外:在SimpleGetAll()函数中,一切都很好,直到Select(info => .GetValue(null))FieldInfo属性本身包含所有4个选项。在CCD_ 9和铸造之后;"活着";。

国家实体如下所示:

public partial class AppState : State<AppState>
{
public IList<SimpleImpl> Simples { get; private set; }
public override void Initialize()
{
Simples = new List<SimpleImpl>();
}
}

这个样本的作用:

public partial class AppState
{
public class AddAction : IAction
{
public AddAction(string simple)
{
Simple = simple;
}
public string Simple { get; }
}
}

此代码在.NET Core 3.1下运行。如果有人能告诉我问题的症结所在,我将不胜感激。

感谢@steven-t-cramer如何帮助我找到问题。基本上,这一切都归结为Mediator.Send和状态处理。

在Blazor State库中,当一个人调度和处理一个操作时,就会创建一个克隆(所以作为开发人员,您不必处理这个问题(。但由于Simple(基本上是一个枚举类(的静态特性,这种克隆在这里搞砸了。

为了解决这个问题,国家可以实现ICloneable,并自行完成这些工作。

一个非常天真的方法是:

public partial class AppState : State<AppState>, ICloneable
{
private List<SimpleImpl> _simples = new List<SimpleImpl>();
public IReadOnlyList<SimpleImpl> Simples => _simples.AsReadOnly();
public override void Initialize()
{
_simples = new List<SimpleImpl>();
}
public object Clone()
{
var state = new AppState { _simples = _simples};
return state;
}
}

最新更新