public async Task DeleteAsync_Ok()
    {
        var deleted   = false;
        var localizer = Context.Services.GetRequiredService <IStringLocalizer <Foo> >();
        var fooData   = GenerateDataTable(localizer);
        var context   = new DataTableDynamicContext(fooData)
        {
            OnDeleteAsync = foos =>
            {
                deleted = true;
                return(Task.FromResult(true));
            }
        };
        var items = context.GetItems();
        await context.DeleteAsync(items);

        Assert.True(deleted);
    }
    public async Task DeleteAsync_Null()
    {
        var actual    = "";
        var deleted   = false;
        var added     = false;
        var localizer = Context.Services.GetRequiredService <IStringLocalizer <Foo> >();
        var fooData   = GenerateDataTable(localizer);
        var context   = new DataTableDynamicContext(fooData)
        {
            OnChanged = args =>
            {
                deleted = args.ChangedType == DynamicItemChangedType.Delete;
                added   = args.ChangedType == DynamicItemChangedType.Add;
                actual  = args.Items.First().DynamicObjectPrimaryKey.ToString();
                return(Task.CompletedTask);
            }
        };
        var item     = context.GetItems().ToList().Take(1);
        var expected = item.First().DynamicObjectPrimaryKey.ToString();
        await context.DeleteAsync(item);

        Assert.Equal(expected, actual);
        Assert.True(deleted);
        Assert.Equal(3, context.GetItems().Count());

        // add
        await context.AddAsync(item);

        Assert.True(added);
        Assert.Equal(4, context.GetItems().Count());

        // add empty
        await context.AddAsync(Enumerable.Empty <IDynamicObject>());

        // 在选中行位置插入
        await context.AddAsync(context.GetItems().Take(2));
    }