繁体   English   中英

通用 Blazor 组件的编译器错误

[英]Compiler error with generic Blazor component

我在 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

解决方案如下:

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" />

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM