【问题标题】:Read file to custom class constructor [closed]将文件读取到自定义类构造函数[关闭]
【发布时间】:2014-01-14 15:14:39
【问题描述】:

我有一个如下所示的文本文件:

Name One, 123, 13.88, 12.25
Name Two, 321, 12.56, 10.75

我需要用我创建的自定义类将它读入一个数组(不能是数组列表),如下所示:

class Stuff
{
    //Stuffconstructor (w/ args)
    public Stuff(string name, int number, decimal rate, double hours)
    {
        System.Console.WriteLine("this constructor has been called");
    }
}

我不太确定如何在 c# 中执行此操作。

【问题讨论】:

  • 你试过什么?你到底卡在哪里了?你知道如何打开/读取文件吗?您需要帮助解析字符串吗?请具体。
  • 在 C# 中可以找到数百个读取/解析文本文件的示例。你有没有尝试过?
  • 我不知道该怎么做。我希望能够逐行读取文件并将其放入自定义类的对象中,以便将文件中的测试按以下顺序放入数组中:字符串、整数、十进制、双精度。我是初学者,不知道怎么做
  • 我找到了一些例子,但它们似乎总是针对同一类型。如果我只是把它放到一个字符串数组中,我没有问题,但我需要数组来接受不同的类型

标签: c# .net class file-io constructor


【解决方案1】:
var parsedList = new List<Stuff>();
string[] lines = System.IO.File.ReadAllLines(@"C:\input.txt");
foreach (var line in lines)
{
    var lineSplit = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    var stuff = new Stuff(lineSplit[0], Int32.Parse(lineSplit[1]), decimal.Parse(lineSplit[2]), double.Parse([3])  );
    parsedList.Add(stuff);
}
Stuff[]  arrayOfStuff = parsedList.ToArray();

【讨论】:

  • 非常感谢您的帮助!
  • :( 用勺子喂“给我密码”的问题让我很难过
  • 我对这个解决方案的一个问题是ReadAllLines()。如果文本文件很大怎么办?没有理由不使用ReadLines()...您已经在使用foreach()
  • 在这种情况下我不能使用列表。你有其他选择吗?
  • 纯粹使用数组,用lines.length 实例化它,然后将foreach 换成for(int i=0;...
【解决方案2】:

您所看到的可能是一个非常通用的示例……您可能想要一些更健壮和可扩展的东西。那么让我来介绍一下reflection

注意

这个解决方案使用反射...这意味着一些事情:

  • 不适合胆小的人...这对于新程序员来说可能看起来很奇怪。
  • 它不擅长性能。反射可能比普通代码慢LITTLE...
  • 为简单起见,我们假设您有一个公共构造函数
  • 同样为简单起见,我们假设构造函数只有具有 Parse() 方法或类型为 String 的参数。

解决方案

public static IEnumerable<T> Extract<T>(String path)
{
  var parseList = buildParser(typeof(T));

  foreach (string line in File.ReadLines(path))
  {
    var tokens = line.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
    var args = parseList.Zip(tokens, (parser, value) => parser(value));

    yield return (T)Activator.CreateInstance(typeof(T), args.ToArray());
  }
}

private static IEnumerable<Func<String, Object>> buildParser(Type t)
{
  // For now, we're going to assume you only have one public constructor.
  var ci = t.GetConstructors().First();

  foreach (var pi in ci.GetParameters())
  {
    var parser = fetchParseMethod(pi.ParameterType);
    Func<String, Object> boxingParser;

    if (parser != null)
      boxingParser = value => parser.Invoke(null, new Object[] { value });
    else
      boxingParser = value => value;

    yield return boxingParser;
  }
}

private static System.Reflection.MethodInfo fetchParseMethod(Type t)
{
  return (from mi in t.GetMethods(System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)
          let parms = mi.GetParameters()
          where mi.Name == "Parse" && parms.Length == 1 && parms.First().ParameterType == typeof(String)
          select mi).FirstOrDefault();
}

然后使用这样的代码:

foreach(var stuff in Extract<Struff>(@"C:\blah.txt"))
{
  // Do something with stuff
}

简要概述

这看起来可能有点费劲……但实际上很简单:

  1. 我们先看下所需类型的构造函数(Stuff
  2. 然后我们遍历构造函数的每个ParameterType 并为其获取Parse() 方法。
  3. 然后我们对文本行的每个元素使用Parse() 方法将其转换为Object
  4. 有了这个,我们可以动态创建一个对象 (Stuff)。

虽然这对你来说可能有点矫枉过正...我玩得很开心,希望我们都能从中学到一些东西。此外,该解决方案非常灵活。如果您稍后向构造函数添加参数,这将自动拾取它。

【讨论】:

    猜你喜欢
    • 2014-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    相关资源
    最近更新 更多