使用泛型 Blazor 组件编译错误

4

我已经在 Blazor 中定义了一个自定义的select组件,就像这样:

public class BetterInputSelect<TItem> : InputBase<TItem>
{
  [Parameter]
  public IEnumerable<TItem> Data { get; set; } = new List<TItem>();

  protected override void BuildRenderTree(RenderTreeBuilder builder)
  {
    builder.OpenElement(0, "select");
    builder.AddMultipleAttributes(1, AdditionalAttributes);
    builder.AddAttribute(2, "class", CssClass);
    builder.AddAttribute(3, "value", BindConverter.FormatValue(CurrentValueAsString));
    builder.AddAttribute(4, "onchange", EventCallback.Factory.CreateBinder<string>(
      this, value => CurrentValueAsString = value, CurrentValueAsString!, null));

    foreach (var item in this.Data)
    {
      builder.OpenElement(5, "option");
      builder.AddAttribute(6, "value", item!.ToString());
      builder.AddContent(7, this.FindDisplayName(item));
      builder.CloseElement();
    }

    builder.CloseElement();
  }

  protected override bool TryParseValueFromString(string? value, out TItem result, out string validationErrorMessage)
  {
    // Check for enums first.
    if (typeof(TItem).IsEnum && BindConverter.TryConvertTo(value, CultureInfo.CurrentCulture, out TItem? parsedValue))
    {
      result = parsedValue!;
      validationErrorMessage = null!;
      return true;
    }

    // Other types here
    // ...

    result = default!;
    validationErrorMessage = $"The {FieldIdentifier.FieldName} field is not valid.";
    return false;
  }

  private string FindDisplayName(TItem value)
  {
    return value switch
    {
      null => string.Empty,
      Enum @enum => @enum.GetDescription(),
      _ => value.ToString() ?? string.Empty
    };
  }
}

然后可以像这样使用:

<BetterInputSelect Data="@Reasons" @bind-Value="@Reason" />

其中ReasonsReason的定义如下:

public SomeReason Reason { get; set; }

private IEnumerable<SomeReason>? Reasons { get; set; }

...

public enum SomeReason 
{
  ...
}

只要被@bind-Value绑定的值不为空,这个方法就能很好地工作。但当我这样做时:
public SomeReason? Reason { get; set; }

我遇到了编译时错误:

[CS0411] The type arguments for method 
'TypeInference.CreateBetterInputSelect_0<TItem>(RenderTreeBuilder, int, int, IEnumerable<TItem>, int, TItem, int, EventCallback<TItem>, int, Expression<Func<TItem>>)' 
cannot be inferred from the usage. Try specifying the type arguments explicitly.

我是否可以不绑定到可空属性,或者有没有办法让编译器满意,我可能错过了什么?

编辑

如果我尝试像这样明确定义类型:

<BetterInputSelect
  Data="@Reasons" 
  @bind-Value="@Reason" 
  TItem="SomeReason" />

然后我得到以下的编译错误:

[CS1503] Argument 1: cannot convert from 'SomeReason?' to 'SomeReason'
[CS1503] Argument 2: cannot convert from 'Microsoft.AspNetCore.Components.EventCallback<SomeReason?>' to 'Microsoft.AspNetCore.Components.EventCallback'
[CS0266] Cannot implicitly convert type 'SomeReason?' to 'SomeReason'. An explicit conversion exists (are you missing a cast?)
[CS1662] Cannot convert lambda expression to intended delegate type because some of the return types in the block are not implicitly convertible to the delegate return type

如果这个程序使用非空的值,我会感到惊讶。即使构造函数参数或属性赋值已知参数类型在编译时,也无法推断出类型。你应该明确指定 TItem 属性的类型。 - Panagiotis Kanavos
@BartKiers 你尝试了什么语法?应该是类似于 TItem="SomeReason" 的东西。 - Kirk Woll
感谢@KirkWoll的建议,我更新了我的问题,并使用TItem="SomeReason"进行了测试。 - Bart Kiers
1
尝试这个: <BetterInputSelect Data="@Reasons" @bind-Value="@Reason" TItem="SomeReason?" /> (使用 SomeReason? 而不是 SomeReason) - Oluwadamilola Adegunwa
1
@DamilolaAdegunwa 那确实是解决方案的一部分:非常感谢! - Bart Kiers
显示剩余3条评论
1个回答

3
解决方案如下:
BetterInputSelect<TItem> 中:
// Was:
//   [Parameter]
//   public IEnumerable<TItem> Data { get; set; } = new List<TItem>();

[Parameter]
public IEnumerable<TItem?> Data { get; set; } = new List<TItem?>();

在我的视图中:

<BetterInputSelect
  Data="@(Reasons as IEnumerable<SomeReason?>)" 
  TItem="SomeReason?"
  @bind-Value="@Reason" />

@Reason既可以为空也可以非空时,此方法有效。非空情况下不需要强制类型转换和明确的类型定义:

<BetterInputSelect
  Data="@Reasons" 
  @bind-Value="@Reason" />

只是想知道你的组件比内置的InputSelect好在哪里。我认为,当你将IEnumerable<TItem>传递给自定义组件而不是使用ChildContent时,它会降低而不是提升。 - enet
内置的InputSelect(据我所知)只能容纳枚举和字符串。它仅显示枚举的值(而我想从枚举和其他对象中提取自定义描述)。 - Bart Kiers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接