TokugawaTakeshi / CrossPlatformOrganizerAppplication

0 stars 0 forks source link

ジェネリックにする事が出来ません #55

Closed TokugawaTakeshi closed 1 year ago

TokugawaTakeshi commented 1 year ago

@gummoni

public partial class TextBox : InputtableControl

public partial class TextBox<TValue, TValidation> : InputtableControl where TValidation : InputtedValueValidation.InputtedValueValidation

に置き換えたら、クラスがpartialではなくなりました(詰まり、「TextBox.razor」との関連性が切れました)が、ジェネリックパラメーターをValidatableControl.Payloadに渡さなければいけません。

public partial class TextBox<TValue, TValidation> : InputtableControl where TValidation : InputtedValueValidation.InputtedValueValidation
{

  protected string rawValue = "";
  protected ValidatableControl.Payload<TValue, TValidation> _payload;

  [Parameter]
  public required ValidatableControl.Payload<TValue, TValidation> payload
  {
    get => _payload;
    set
    {
      this._payload = value;
      this.synchronizeRawValueWithPayloadValue();
    }
  }

}

Image

どうすれば宜しいでしょうか?

gummoni commented 1 year ago

Razorのビヘイビアクラスでジェネリックは対応していないようなので、

public partial class TextBox<TValue, TValidation> : ...

というような記述を行うとエラーがでるようです。

解決方法は、ジェネリックにせずに ・TValueとTValidationにはObjectを指定して、プロパティ経由でType情報を渡す。 ・インターフェイス型を渡す。 があります。

それと上記変更に伴って、Payloadクラスの部分も併せて変更が必要になってきます。 こちらは、 ・両方ともobject型で受けれるようにするか ・非ジェネリックのPayloadを用意するか ・インターフェイス型を渡してPayload内部で型解析するか 上記、対処方法が考えられます。

どちらにしても ・非ジェネリックで後から型情報を渡す ・インターフェイスに切り替える などの調整が必要となります。

TokugawaTakeshi commented 1 year ago

@gummoni

なるほど・・・ 仕方あるまい、頑張ってオブジェクトやインターネットを使って実装します。

支援、感謝します。

TokugawaTakeshi commented 1 year ago

@gummoni

TValueobjectにしました。 現在、そのままでthis.controlsPayload.familyName.GetExpectedToBeValidValue();this.targetPerson.familyNameに割り当てますと、当然Cannot convert source type 'object' to target type 'string'エラーが発生します。

public partial class PersonManager : Microsoft.AspNetCore.Components.ComponentBase
{

  private void updatePersonIfInputtedDataIsValid()
  {

    if (this.targetPerson is null)
    {
      throw new Exception("「updatePersonIfInputtedDataIsValid」メソッドは呼び出されたが、「targetPerson」は「null」のまま。");
    }

    if (ValidatableControlsGroup.HasInvalidInputs(this.controlsPayload))
    {
      ValidatableControlsGroup.PointOutValidationErrors(this.controlsPayload);
    }

    this.targetPerson.familyName = this.controlsPayload.familyName.GetExpectedToBeValidValue();

  }

}

現在、GetExpectedToBeValidValueの実装は

public class Payload
{

  protected object value;

  protected readonly InputtedValueValidation validation;

  protected InputtedValueValidationResult validationResult;

  protected Func<IValidatableControl> componentInstanceAccessor;

  public object Value
  {
    get => this.value;
    set {
      this.value = value;
      this.validationResult = this.validation.Validate(this.value);
    }
  }

  // ...

  public object GetExpectedToBeValidValue()
  {

    if (this.IsInvalid)
    {
      throw new Exception("Contrary to expectations, the value is invalid.");
    }

    return this.Value;

  }

}

です。型テックと、キャストをGetExpectedToBeValidValueの中にやりたいと思います。 下記は妥当なコードになってはいませんが、その様に実装できますか?

public class Payload
{
    // ...
  public object GetExpectedToBeValidValue<TValue>()
  {

    if (this.IsInvalid)
    {
      throw new Exception("Contrary os expectations, the value is invalid.");
    }

        if (this.Value is TValue narrowedValidValue) {
          return (TValue) narrowedValidValue;
        }

    throw new Exception("対象値の型は期待型と異なります。");

  }

}

尚、値は任意な時、nullになっている事も有り得える事を考慮する必要があります。

gummoni commented 1 year ago

この場合ならば

  public object GetExpectedToBeValidValue<TValue>()
  {

    if (this.IsInvalid)
    {
      throw new Exception("Contrary os expectations, the value is invalid.");
    }

    if (this.Value is TValue narrowedValidValue) return narrowedValidValue;

    throw new Exception("対象値の型は期待型と異なります。");

  }

上記のようにメソッドにジェネリック型を用意して 関数内で型チェックを行う方法があります。

このような型チェックで実装していく手法をリフレクションプログラミングといって、型情報を用いてプログラムを書いていきます。

このプログラミングの参考URLを記載します。 https://qiita.com/gushwell/items/91436bd1871586f6e663

TokugawaTakeshi commented 1 year ago

@gummoni

ありがとう、動かしました。 ただ一つ、public object GetExpectedToBeValidValue<TValue>()public TValue GetExpectedToBeValidValue<TValue>()に変える必要があります。