【发布时间】:2020-05-28 07:57:03
【问题描述】:
我正在尝试基于字符串参数创建类型并将其传递给构造函数的类型参数。仅使用 if 语句检查它会变得非常讨厌,而且我不知道如何以编程方式/通用方式进行更多操作。
我尝试过反射,但只返回一个对象并将一个对象传递给
有没有人知道如何在没有数千个 if 语句的情况下以更微妙的方式解决这个问题?
对象创建如下所示:
if (Options.Input1Type == "int" && Options.Output1Type == "int") return BlockBuilder.Build<int, int>(Kind, Options, TransformToSelf);
if (Options.Input1Type == "bool" && Options.Output1Type == "bool") return BlockBuilder.Build<bool, bool>(Kind, Options, TransformToSelf);
if (Options.Input1Type == "string" && Options.Output1Type == "string") return BlockBuilder.Build<string, string>(Kind, Options, TransformToSelf);
if (Options.Input1Type == "bool" && Options.Output1Type == "int") return BlockBuilder.Build<bool, int>(Kind, Options, TransformToInt);
if (Options.Input1Type == "bool" && Options.Output1Type == "string") return BlockBuilder.Build<bool, string>(Kind, Options, TransformToString);
if (Options.Input1Type == "int" && Options.Output1Type == "bool") return BlockBuilder.Build<int, bool>(Kind, Options, TransformToBool);
if (Options.Input1Type == "int" && Options.Output1Type == "string") return BlockBuilder.Build<int, string>(Kind, Options, TransformToString);
if (Options.Input1Type == "string" && Options.Output1Type == "int") return BlockBuilder.Build<string, int>(Kind, Options, TransformToInt);
if (Options.Input1Type == "string" && Options.Output1Type == "bool") return BlockBuilder.Build<string, bool>(Kind, Options, TransformToBool);
BlockBuilder 看起来像这样:
public static IDataflowBlock Build<TIn, TOut>(string kind, BlockOptions blockOptions, Func<TIn, TOut> singleOutputExecutionFunction = null, Func<TIn, IEnumerable<TOut>> multipleOutputExecutionFunction = null)
{
if (singleOutputExecutionFunction == null && multipleOutputExecutionFunction == null)
throw new ArgumentException("Missing function to execute");
Enum.TryParse(kind, out TransformationBlocks Kind);
switch (Kind)
{
case TransformationBlocks.Undefined:
throw new ArgumentException("No block type was specified");
case TransformationBlocks.TransformBlock:
return new TransformBlock<TIn, TOut>(param => { return singleOutputExecutionFunction(param); }, new ExecutionDataflowBlockOptions()
{
MaxMessagesPerTask = blockOptions.MaxMessagesPerTask,
BoundedCapacity = blockOptions.BoundedCapacity,
MaxDegreeOfParallelism = blockOptions.MaxDegreeOfParallelism,
});
case TransformationBlocks.TransformManyBlock:
return new TransformManyBlock<TIn, TOut>(param => { return multipleOutputExecutionFunction(param); }, new ExecutionDataflowBlockOptions()
{
MaxMessagesPerTask = blockOptions.MaxMessagesPerTask,
BoundedCapacity = blockOptions.BoundedCapacity,
MaxDegreeOfParallelism = blockOptions.MaxDegreeOfParallelism,
});
default:
return default;
}
}
委托/函数如下所示:
private static T TransformToSelf<T>(T obj)
{
return obj;
}
private static string TransformToString<T>(T obj)
{
return Convert.ToString(obj);
}
private static int TransformToInt<T>(T obj)
{
return Convert.ToInt32(obj);
}
private static bool TransformToBool<T>(T obj)
{
return Convert.ToBoolean(obj);
}
【问题讨论】:
-
用查找表替换那些
if语句会更好,这样它就不会看起来那么糟糕/重复。此外,C#8(或者可能是 9)对这种模式有更好的 switch/case 处理 -
顺便说一句,您可能应该将
TransformXX方法中的T限制为IConvertible,否则您将失去它可以与Convert类一起使用的保证。此时,您可以通过静态方法调用接口上的方法。您还可以将所有这些方法简化为对(T)Convert.ChangeType(obj, typeof(T))的一次调用,这要求类型为IConvertible。您也应该能够约束TIn和TOut——这可能对整体解决方案有帮助,也可能没有帮助 -
感谢两位的提示!我利用了它们并设法以一种非常优雅的方式做到了这一点。
标签: c# generics types task-parallel-library dataflow