鉴于您的要求,我想出了一个有趣的解决方案。尽管如此,它可能比使用所述String.SubString()
方法更复杂和更长。
但是,此解决方案可转移到其他类型和其他字符串。我使用了 、 和 的概念Attributes
来Properties
按Reflection
固定长度解析字符串并设置类属性。
请注意,我确实更改了您的StudentData
课程以遵循更传统的编码风格。按照 MSDN 上的这个方便的指南:http: //msdn.microsoft.com/en-us/library/xzf533w0 (v=vs.71).aspx
这是新StudentData
课程。请注意,它使用属性而不是字段。(这里不讨论)。
public class StudentData
{
string name;
string age;
string address;
string bday;
string level;
[FixedLengthDelimeter(0, 20)]
public string Name { get { return this.name; } set { this.name = value; } }
[FixedLengthDelimeter(1, 3)]
public string Age { get { return this.age; } set { this.age = value; } }
[FixedLengthDelimeter(2, 30)]
public string Address { get { return this.address; } set { this.address = value; } }
[FixedLengthDelimeter(3, 10)]
public string BDay { get { return this.bday; } set { this.bday = value; } }
[FixedLengthDelimeter(4, 3)]
public string Level { get { return this.level; } set { this.level = value; } }
}
请注意,每个属性都有一个名为的 Attribute FixedLengthDelimeter
,它接受两个参数。
OrderNumber
FixedLength
参数表示字符串中的OrderNumber
顺序(不是位置),而是我们从字符串中处理的顺序。第二个参数表示Length
解析字符串时的字符串。这是完整的属性类。
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FixedLengthDelimeterAttribute : Attribute
{
public FixedLengthDelimeterAttribute(int orderNumber, int fixedLength)
{
this.fixedLength = fixedLength;
this.orderNumber = orderNumber;
}
readonly int fixedLength;
readonly int orderNumber;
public int FixedLength { get { return this.fixedLength; } }
public int OrderNumber { get { return this.orderNumber; } }
}
现在属性很简单。接受我们之前在构造函数中讨论过的两个参数。
最后还有另一种方法可以将字符串解析为对象类型,例如。
public static class FixedLengthFormatter
{
public static T ParseString<T>(string inputString)
{
Type tType = typeof(T);
var properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public); //;.Where(x => x.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false).Count() > 0);
T newT = (T)Activator.CreateInstance(tType);
Dictionary<PropertyInfo, FixedLengthDelimeterAttribute> dictionary = new Dictionary<PropertyInfo, FixedLengthDelimeterAttribute>();
foreach (var property in properties)
{
var atts = property.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false);
if (atts.Length == 0)
continue;
dictionary[property] = atts[0] as FixedLengthDelimeterAttribute;
}
foreach (var kvp in dictionary.OrderBy(x => x.Value.OrderNumber))
{
int length = kvp.Value.FixedLength;
if (inputString.Length < length)
throw new Exception("error on attribute order number:" + kvp.Value.OrderNumber + " the string is too short.");
string piece = inputString.Substring(0, length);
inputString = inputString.Substring(length);
kvp.Key.SetValue(newT, piece.Trim(), null);
}
return newT;
}
}
上面的方法就是解析字符串。这是一个非常基本的实用程序,可以读取FixedLengthDelimeter
应用了属性的所有属性Dictionary
。然后枚举该字典(按 排序OrderNumber
),然后SubString()
在输入字符串上调用该方法两次。
第一个子字符串用于解析下一个子字符串,Token
而第二个子字符串重置inputString
以开始处理下一个令牌。
最后,当它解析字符串时,它会将解析的字符串应用于Type
提供给方法的类的属性。
现在可以像这样简单地使用它:
string data1 = "Jonh Smith 016Some place in NY, USA 01/01/2014L01";
StudentData student = FixedLengthFormatter.ParseString<StudentData>(data1);
这是做什么的:
这不做什么:
- 它确实将解析的字符串转换为另一种类型。因此,所有属性都必须是字符串。(这可以通过添加一些类型转换逻辑来轻松调整)。
- 它没有经过很好的测试。这仅针对少数样本进行测试。
- 这绝不是唯一或最好的解决方案。