简体   繁体   中英

Compiler error with generic Blazor component

I've defined a custom select component in Blazor like this:

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
    };
  }
}

which can then be used like this:

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

where Reasons and Reason are defined like this:

public SomeReason Reason { get; set; }

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

...

public enum SomeReason 
{
  ...
}

This works great as long as the value that is bound by @bind-Value is not nullable. When I do:

public SomeReason? Reason { get; set; }

I get a compile time error:

[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.

Can I simply not bind to a nullable property, or is there a way to make the compiler happy that I've missed?

EDIT

And if I try to define the type explicitly like this:

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

then I get the following compiler errors:

[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

The solution was as follows:

In BetterInputSelect<TItem> :

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

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

and in the view I did:

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

which works when @Reason is nullable- and non-nullable. The non-nullable would of course not need a cast and explicit type definition:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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