有没有一种方法可以将字符串转换成类型?

4
我正在学习C#中的泛型。对于有经验的人来说,这可能很简单。
我有71个不同的模型,我想能够使用泛型将数据从CSV通用地存储到它们中。
处理部分并不是特别难,我有这个方法签名:
private static async Task ProcessFileAsync<T>(string currentFile) where T : class, new()

难点在于如何调用它。我有一个CSV文件,每个模型都需要将数据放入其中。CSV文件的名称与模型的名称相同(例如:Product.csv对应Product模型)。

理想情况下,我希望只需在调用者中发送名称,但我收到了“X是变量,但像类型一样使用”的编译器错误。

我可以有一个庞大的switch语句来解决这个问题,但这似乎相当浪费。

任何帮助将不胜感激。

换句话说,我可以采取以下方法:

        switch(justFName)
        {
            case "Address":
                _ = ProcessFileAsync<Address>(ci.FullName);
                break;
            case "Currency":
                _ = ProcessFileAsync<Currency>(ci.FullName);
                break;
                ...
                ...
                ...And so on
                ...
                ...
            default:
                //No method for this file name
                break;
        }

相反,我希望有类似这样的内容:

_ = ProcessFileAsync<justFName>(ci.FullName);

这些 CSV 文件是来自另一个应用程序吗?有 JSON 和 XAML 序列化可以为您完成此类操作。 - Felix Castor
是的,我已经手头有CSV文件了。 - snussel
如果您能够发布一些代码来展示您想要实现的内容,那就太好了。 - Tarik
2个回答

3
如果你可以从程序集中确定所有需要处理的类(我个人喜欢用特别创建的属性标记它们),那么反射表达式树就能派上用场:
public class Address { }

public class MethodHolder // Just dummy class to hold your process action
{
    public static async Task ProcessFileAsync<T>(string currentFile) where T : class, new()
    {
        Console.WriteLine(currentFile);
    }
}

public static class Processor
{
    private static readonly Dictionary<string, Action<string>> _dict;
    static Processor()
    {
        var types = typeof(Address).Assembly.GetTypes()
            // filter your types correctly here somehow
            // JIC do not forget to verify that they satisfy
            // your generic constraints
            .Where(t => t.Name == "Address");
        _dict = types.ToDictionary(t => t.Name, BuildAction);
    }

    private static Action<string> BuildAction(Type t)
    {
        var method = typeof(MethodHolder).GetMethod(nameof(MethodHolder.ProcessFileAsync))
        .MakeGenericMethod(t);

        var param = Expression.Parameter(typeof(string));
        return Expression.Lambda<Action<string>>(
                Expression.Call(method, param), 
                param)
            .Compile();
    }

    // TODO: add some nice handling for keys not in dictionary
    public static void Process(string key, string value) => _dict[key](value);
}

使用方法:Processor.Process(nameof(Address), "testfilename");nameof 只是为了举例)


0

@GuruStron的回答非常好。另一种实现你所需的方法是只使用反射。然而,就像@GuruStrong建议的那样,最好在搜索将要执行的类中包含一个注释,或将它们放在单个程序集中。以下代码仅在这些类位于同一程序集中时才有效。

#region These classes must be in the same assembly
public class Address {
}

public class Currency {
} 
#endregion

class Program {
    static async Task Main(string[] args) {
        var justFName = "Currency";
        var fullName = "name";
        var type = typeof(Address).Assembly.GetTypes()
            .Single(x => x.Name == justFName);
        var method = typeof(Program).GetMethod(nameof(ProcessFileAsync),
                BindingFlags.NonPublic | BindingFlags.Static)
            .MakeGenericMethod(type);
        await (Task)method.Invoke(null, new object[] { fullName });

        Console.ReadLine();
    }

    private static async Task ProcessFileAsync<T>(string currentFile) where T : class, new() {
        Console.WriteLine(currentFile);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接