我们正在使用。net 7下的服务器端Blazor创建一个LOB应用程序/站点。在每个列表上,我们都有一个下载CSV文件的按钮。对于一次性的东西来说,工作得很好,但它有很多重复的代码,并且必须在任何地方进行更改。输入……(ta-da…)通用组件!
我把所有需要的东西都包装到一个组件中,我的下载按钮就像预期的那样工作了。我们下载的每个东西都定义了一个POCO/EF类。我可以把这个类作为TypeParm (<T>)
传递给我的组件。
我的问题是大多数这些类都有一个匹配的Map类。有些事情我不完全理解(泛型不是我的强项),但是Blazor组件在处理多个泛型类型时遇到了麻烦。
如果有可能传递一个<T>
和一个,比如<U>
,我不知道怎么做。有一些关于部分类和泛型的文章,并且在早期的Blazor/razor版本中可能存在一些错误。
我可以将类型类映射的NAME作为字符串传递,但我不知道如何传递类或如何将TypeName的字符串变为类本身以调用RegisterClassMap
。
如果有人能分享这个神奇的酱汁,或者告诉我去哪里获取更多的信息,我将非常感激。
在评论这些建议(在发布之前)时,我没有看到类似的东西,但我想知道这种方法是否会有一个超类:
public class TypeForCSV
{
object TheListClass,
object TheMapClass
}
但我(个人)仍然会纠结于如何定义它以使其通用。
谢谢大家。
这是我的组件。评论栏是我的问题。(是的,我们也使用MudBlazor)
@using BlazorDownloadFile
@typeparam T
<MudButton Variant="@(_processing ? Variant.Filled : Variant.Outlined )"
DisableElevation="true"
Size="Size.Small"
Color="Color.Primary"
StartIcon="@(_processing ? "" : Icons.Filled.BrowserUpdated)"
OnClick="@ExportToCSV"
Disabled="@_processing"
Class="ma-2 mt-8">
@if (_processing)
{
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
<span> Preparing...</span>
}
else
{
<span>Export CSV</span>
}
</MudButton>
@code {
private bool _processing = false;
[Inject] public IBlazorDownloadFileService? BlazorDownloadFileService { get; set; }
[Parameter] public string FileNameBase { get; set; } = "";
[Parameter] public string CsvMapType { get; set; } = "NothingToSeeHere";
[Parameter] public Func<Task<List<T>>>? OnListRequest { get; set; }
public List<T> ListItems { get; set; } = new();
private string _csv = "";
private string MakeCsvString(List<T> items)
{
using (var writer = new StringWriter())
using (var csv1 = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
// csv1.Context.RegisterClassMap<U>(); // use a different overload?
csv1.WriteRecords(items);
return writer.ToString();
}
}
private async Task ExportToCSV()
{
_processing = true;
StateHasChanged();
ListItems = await OnListRequest();
_csv = MakeCsvString(ListItems);
string filename = $"{FileNameBase.IfNullOrWhiteSpace("Download")}-{DateTime.Now:yyyyMMdd-HHmm}.csv";
await BlazorDownloadFileService.DownloadFileFromText(filename, _csv, System.Text.Encoding.UTF8, "text/csv");
await Task.Yield();
_processing = false;
StateHasChanged();
}
}
根据Craig Brown对的回答,泛型类型约束在blazor中可能吗?,从开始。网6您可以在Blazor中使用通用约束。由于使用的是。net 7,您可以定义第二个泛型参数,并将其约束为ClassMap<T>
,如下所示:
@typeparam TMap where TMap : CsvHelper.Configuration.ClassMap<T>
所以你的完整代码可能看起来像:
@using BlazorDownloadFile
@typeparam T
@typeparam TMap where TMap : CsvHelper.Configuration.ClassMap<T>
<MudButton Variant="@(_processing ? Variant.Filled : Variant.Outlined )"
DisableElevation="true"
Size="Size.Small"
Color="Color.Primary"
StartIcon="@(_processing ? "" : Icons.Filled.BrowserUpdated)"
OnClick="@ExportToCSV"
Disabled="@_processing"
Class="ma-2 mt-8">
@if (_processing)
{
<MudProgressCircular Class="ms-n1" Size="Size.Small" Indeterminate="true" />
<span> Preparing...</span>
}
else
{
<span>Export CSV</span>
}
</MudButton>
@code {
private bool _processing = false;
[Inject] public IBlazorDownloadFileService? BlazorDownloadFileService { get; set; }
[Parameter] public string FileNameBase { get; set; } = "";
[Parameter] public Func<Task<List<T>>>? OnListRequest { get; set; }
public List<T> ListItems { get; set; } = new();
private string _csv = "";
private string MakeCsvString(List<T> items)
{
using (var writer = new StringWriter())
using (var csv1 = new CsvWriter(writer, CultureInfo.InvariantCulture))
{
csv1.Context.RegisterClassMap<TMap>();
csv1.WriteRecords(items);
return writer.ToString();
}
}
private async Task ExportToCSV()
{
_processing = true;
StateHasChanged();
ListItems = await OnListRequest();
_csv = MakeCsvString(ListItems);
string filename = $"{FileNameBase.IfNullOrWhiteSpace("Download")}-{DateTime.Now:yyyyMMdd-HHmm}.csv";
await BlazorDownloadFileService.DownloadFileFromText(filename, _csv, System.Text.Encoding.UTF8, "text/csv");
await Task.Yield();
_processing = false;
StateHasChanged();
}
}
您可以传入任意多的泛型类型,每个类型都有限制。
组件:
@typeparam TRecord where TRecord: class, new()
@typeparam TService where TService: class, IService<TRecord>
@typeparam TBase where TBase: class, IDisposable
<h3>Component</h3>
@code {
}
:
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<Component TBase=TestBaseClass TRecord=TestTRecord TService=TestService />
@code {
}
我建议使用接口来限定可以传递的类,并为泛型类型使用描述性名称,而不是T
和U
,以使代码更具可读性。