我正在尝试基于字符串参数创建类型,并将其传递给构造函数的类型参数。仅使用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);
}
这不容易,但是可行。
如果您可以将Input1Type
和Input2Type的类型更改为System.Type而不是字符串,则容易得多。
如果没有,那么我建议您创建一个@neil所建议的映射函数,该函数将字符串映射到类型,然后使用MethodInfo.MakeGenericType()
调用您的Build()
函数。
请参见下面的MakeGenericType()
的简单示例。
using System;
using System.Reflection;
namespace make_generic_type
{
class Program
{
static void Main(string[] args)
{
// Normal C# usage
var host = new Host();
Console.WriteLine(host.GenericMethod<int, string>("Test"));
// Use reflection to get type definition
var unboundMethod = typeof(Host).GetMethod(nameof(Host.GenericMethod));
// As the method is generic, you need to pass the type parameters in.
// We do this by binding the type parameters with MethodInfo.MakeGenericMethod();
var boundMethod = unboundMethod.MakeGenericMethod(new Type[]{ typeof(int), typeof(string) });
// Now we have a method that we can invoke via reflection as normal
Console.WriteLine(boundMethod.Invoke(new Host(), new object[]{ "Test"}));
}
}
class Host{
public string GenericMethod<TIn, TOut>(string kind)
{
return $"{typeof(TIn).Name}; {typeof(TOut).Name}; {kind};";
}
}
}