如何在C#中用未知的键名和成对数量注释元组?

huangapple go评论57阅读模式
英文:

How to annotate the tuple with unknown at advance keys names and pairs number in C#?

问题

The method HasInvalidInputs accepts the tuple with keys and values, herewith the number of pairs, and also keys names are unknown at advance.

public class ValidatableControlsGroup
{
  public static bool HasInvalidInputs(object /* TODO specify more exact type */ controlsPayload)
  {
    // TODO implement
    return true;
  }
}

If it was TypeScript, in the above code it will be { [key: string]: ValidatableControl.Payload } instead of object. The usage of ValidatableControlsGroup.Payload could be:

public partial class TaskManager : ComponentBase
{
  private (ValidatableControl.Payload taskTitle, ValidatableControl.Payload taskDescription) controlsPayload = (
    taskTitle: new ValidatableControl.Payload(initialValue: "", new TaskTitleInputtedDataValidation()),
    taskDescription: new ValidatableControl.Payload(initialValue: "", new TaskTitleInputtedDataValidation())
  );
	
  private void updateTask()
  {
    if (ValidatableControlsGroup.HasInvalidInputs(this.controlsPayload))
    {
      ValidatableControlsGroup.PointOutValidationErrors(this.controlsPayload);
      return;
    }

    this.targetTask.Title = this.controlsPayload.taskTitle.GetExpectedToBeValidValue();
    this.targetTask.Description = this.controlsPayload.taskDescription.GetExpectedToBeValidValue();

    // ...
  }
}

Inside TaskManager, we need to access each ValidatableControl.Payload by key, which is why I want to use the tuple with keys. If it were TypeScript, the type of controlsPayload would be { taskTitle: ValidatableControl.Payload; taskDescription: ValidatableControl.Payload }, which is compatible with the generalized { [key: string]: ValidatableControl.Payload } parameter of ValidatableControlsGroup.HasInvalidInputs.

Please note that enumerating like if (ValidatableControlsGroup.HasInvalidInputs(item1, item2, item3, item4)) is not allowed because ValidatableControlsGroup is being developed as a library class, thus it takes care of routines like the extraction of elements from the tuple.

Lastly, in my case, the HasInvalidInputs method needs only values, but not keys. However, if transforming to an array is required, the HasInvalidInputs method, as the library class, must take care of this routine.

Regarding my case, the HasInvalidInputs method does not need the keys - only the values. However, the keys are required in TaskManager. If the types of controlsPayload parameter are set to ValidatableControl.Payload[], the library user will be forced to transform the tuple to an array, which is unacceptable for a library class because the library class must take care of such routines.

英文:

The method HasInvalidInputs accepts the tuple with keys and values, herewith the number of pairs, and also keys names are unknown at advance.

public class ValidatableControlsGroup
{

  public static bool HasInvalidInputs(object /* TODO specify more exact type */ controlsPayload)
  {
    // TODO implement
    return true;
  }
}

If it was the TypeScript, in above code it will be { [key: string]: ValidatableControl.Payload } instead of object. The usage of ValidatableControlsGroup.Payload could be:

public partial class TaskManager : ComponentBase
{
  private (ValidatableControl.Payload taskTitle, ValidatableControl.Payload taskDescription) controlsPayload = (
    taskTitle: new ValidatableControl.Payload(initialValue: "", new TaskTitleInputtedDataValidation()),
    taskDescription: new ValidatableControl.Payload(initialValue: "", new TaskTitleInputtedDataValidation())
  );
	
  private void updateTask()
  {

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


	this.targetTask.Title = this.controlsPayload.taskTitle.GetExpectedToBeValidValue();
    this.targetTask.Description = this.controlsPayload.taskDescription.GetExpectedToBeValidValue();

    // ...

  }
}

Inside TaskManager we need to access to each ValidatableControl.Payload by key that is why I want to use the tuple with keys.
If it was the TypeScript, the type of controlsPayload was { taskTitle: ValidatableControl.Payload; taskDescription: ValidatableControl.Payload } which is compatible with generalized { [key: string]: ValidatableControl.Payload } of parameter of ValidatableControlsGroup.HasInvalidInputs.

Please note that the enumerating like if (ValidatableControlsGroup.HasInvalidInputs(item1, item2, item3, item4)) is not allowed because the ValidatableControlsGroup is being developed as library class thus it take care about routines like extraction of the elements from the tuple.

Lastly, in my case the HasInvalidInputs method needs only values, but not keys.
However, if the transforming to array required, the HasInvalidInputs as the library class must take care about this routine.

Regarding my case HasInvalidInputs method does not need the keys - it is enough the values.
However, the keys are required in TaskManager. If will set the types of controlsPayload parameter to ValidatableControl.Payload[], the library user will be forced to transform the tuple to array that is unacceptable for library class because the library class must take care about such routines.

答案1

得分: 2

以下是翻译好的部分:

你可以使用泛型:

public void Foo<TKey, TValue>((TKey Key, TValue Value) tuple)
{
    Console.WriteLine(tuple.Key);
}

var f = ("foo", "bar");
Foo(f);

然而,个人观点:

ValidatableControlsGroup 正在作为库类开发,因此它负责从元组中提取元素等例行程序。

然后只需定义一个接口,并将其用于方法参数类型。不应该从库代码中公开或接受值元组。它们应该最多跨越一个边界,最好在同一个程序集内。但这是我的个人观点。

英文:

You could use generics:

public void Foo&lt;TKey, TValue&gt;((TKey Key, TValue Value) tuple)
{
    Console.WriteLine(tuple.Key);
}

var f = (&quot;foo&quot;, &quot;bar&quot;);
Foo(f);

However, opinion time:

> ValidatableControlsGroup is being developed as library class thus it take care about routines like extraction of the elements from the tuple.

Then just define an interface and use that for the method parameter type. Value tuples should not be exposed from or accepted by library code. They should be used to cross one boundary at most, preferably within the same assembly. But that's IMHO.

答案2

得分: 2

以下是要翻译的内容:

事实上,ValueTuple 家族的成员都是 struct。因此,如果您需要表示它们的类型,object 似乎是唯一的选择。

另一种方法是添加一堆重载的方法,以涵盖可能传递的元组类型,然后将它们转换为数组。

public static bool HasInvalidInputs(ValueTuple<ValidatableControl.Payload> controlsPayload)
    => HasInvalidInputs(controlsPayload.Item1);

public static bool HasInvalidInputs(ValueTuple<ValidatableControl.Payload, ValidatableControl.Payload> controlsPayload)
    => HasInvalidInputs(controlsPayload.Item1, controlsPayload.Item2);

......

private static bool HasInvalidInputs(params object[] controlsPayload)
{
}

一言以蔽之,您的问题在于找不到适合此方法的参数类型。也许您应该重新考虑接口。

英文:

The fact is the members of the ValueTuple family are all structs. So if you need a type to represent them, object seems to be the only choice.

Another approach is adding a bunch of overloaded methods to cover the tuple types you may pass in, and then convert them to arrays.

public static bool HasInvalidInputs(ValueTuple&lt;ValidatableControl.Payload&gt; controlsPayload)
	=&gt; HasInvalidInputs(controlsPayload.Item1);

public static bool HasInvalidInputs(ValueTuple&lt;ValidatableControl.Payload, ValidatableControl.Payload&gt; controlsPayload)
	=&gt; HasInvalidInputs(controlsPayload.Item1, controlsPayload.Item2);

......

private static bool HasInvalidInputs(params object[] controlsPayload)
{
}

In a word, your issue is that you cannot find a suitable parameter type for this method. Perhaps you should reconsider the interface.

huangapple
  • 本文由 发表于 2023年5月24日 18:40:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76322626.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定