如何通过反射检索串并连接它上升-LY

我有一个已经被分成很多采用以下模式较小的字符串的长字符串:

Public Class Test Public Prefix_1 as String = "1 to 100 bytes" Public Prefix_2 as String = "101 to 200 bytes" Public Prefix_3 as String = "201 to 300 bytes" Public Prefix_4 as String = "301 to 400 bytes" 'and so on End Class

而这个Test class已被编译为类库项目(即.dll文件)并保存到C:\ Test.dll的

请注意,我有多少没有先验知识Prefix_的dll文件存在的字符串。

我的问题是:如何检索以启动所有字符串Prefix_ 通过反射并连接它上升-LY(即Prefix_1&Prefix_2 ...)成一个字符串?

更新赏金:

赏金只适用于在VB.NET解决方案的答案

--------------解决方案-------------

这应该让你开始。 对不起,这是C#,但我不记得lambda语法。

Type type = Assembly.LoadFrom (@"c:\test.dll").GetType ("Test");
object instance = type.GetConstructor (Type.EmptyTypes).Invoke (null);
var fields = type.GetFields ().Where (f => f.Name.StartsWith ("Prefix_")).OrderBy(f => f.Name);
string x = fields.Aggregate (new StringBuilder (), (sb, f) => sb.Append((string)f.GetValue (instance)), sb => sb.ToString ());

VB.NET

Dim type As Type = Assembly.LoadFrom("c:\test.dll").GetType("Test")
Dim instance As Object = Type.GetConstructor(Type.EmptyTypes).Invoke(Nothing)
Dim fields = _
type.GetFields() _
.Where(Function(f) f.Name.StartsWith("Prefix_")) _
.OrderBy(Function(f) f.Name)
Dim bigString As String = _
fields.Aggregate(New StringBuilder(), _
Function(sb, f) sb.Append(DirectCast(f.GetValue(instance), String)), _
Function(sb) sb.ToString())

如果字符串以相同的顺序定义为你的问题,你能避免排序,这里是一个简单的VB.NET的答案:

Public Function Extract() As String
Dim type As Type = Assembly.LoadFrom("C:\test.dll").GetType("YourNamespace.Test")
Dim instance As Object = Activator.CreateInstance(type)
Dim sb As New StringBuilder
Dim field As FieldInfo
For Each field In type.GetFields
If field.Name.StartsWith("Prefix_") Then
sb.Append(field.GetValue(instance))
End If
Next
Return sb.ToString
End Function

否则这里是排序的函数:

Public Function Extract() As String
Dim type As Type = Assembly.LoadFrom("c:\test.dll").GetType("YourNamespace.Test")
Dim fields As New List(Of FieldInfo)
Dim field As FieldInfo
For Each field In type.GetFields
If field.Name.StartsWith("Prefix_") Then
fields.Add(field)
End If
Next

fields.Sort(New FieldComparer)

Dim sb As New StringBuilder
Dim instance As Object = Activator.CreateInstance(type)
For Each field In fields
sb.Append(field.GetValue(instance))
Next
Return sb.ToString
End Function

Private Class FieldComparer
Implements IComparer(Of FieldInfo)

Public Function Compare(ByVal x As FieldInfo, ByVal y As FieldInfo) As Integer Implements IComparer(Of FieldInfo).Compare
Return x.Name.CompareTo(y.Name)
End Function
End Class

我想提出基于你的答案面向对象的解决方案,在Visual Basic中为你的要求。

免责声明:

请记住,我不是一个VB.NET开发。 我公司提供的代码进行了测试和运行,但肯定需要一些特定语言的改进。

我假设您正在使用的一个实例工作Test ,因为它暴露了字段不Shared

大意

分析你的要求,我发现是非常重要的:

  • 集中在一个地方等领域的命名策略,以便您的解决方案是mantenible
  • 就拿字段排序的照顾。 如果你有Prefix_1,Prefix_2和Prefix_11你可以得到整理,然后错误的方式:Prefix_1,Prefix_11和Prefix_2。
  • 验证没有缺失的字段名(即从跳跃到Prefix_1 Prefix_3)

从你问什么,我模仿各自持有的字符串块在一个名为类中的字段的StringChunkField 。 这每一类车型前缀场拿着串的一大块,并具有以下职责:

  • 提供了有关该领域本身的信息:姓名,编号,保存字符串的块和人物在其中的数
  • 关于集中格式的信息和编号来命名的字段。 这里被定义前缀查找,并在同场的名称的数量开始。
  • 从前面的项目,它可以回答一个字段是一个beginnig一个字符串与否,以及是否字段是StringChunkField与否。
  • 实现IComparable的集中在一个地方排序逻辑(它是基于字段编号)

    Imports System.Reflection

    Friend Class StringChunkField
    Implements IComparable(Of StringChunkField)

    #Region "Fields"
    Private ReadOnly _number As Integer
    Private _name As String
    Private _stringChunk As String
    Private Shared _beginningOfStringFieldNumber As Integer = 1
    Private Shared _namePrefix As String = "Prefix_"

    #End Region

    Public Sub New(ByRef field As FieldInfo, ByRef target As Object)
    _name = field.Name
    _stringChunk = field.GetValue(target)
    _number = ExtractFieldNumber(field.Name)
    End Sub

    #Region "Properties"

    ' Returns the field's number
    Public ReadOnly Property Number() As Integer
    Get
    Return _number
    End Get
    End Property

    ' Returns the field's name (includes the number also)
    Public ReadOnly Property Name() As String
    Get
    Return _name
    End Get
    End Property

    ' Returns the chunk of the string this fields holds
    Public ReadOnly Property StringChunk() As String
    Get
    Return _stringChunk
    End Get
    End Property

    ' Returns the number of characters held in this field
    Public ReadOnly Property NumberOfCharacters() As Integer
    Get
    If (String.IsNullOrEmpty(StringChunk)) Then
    Return 0
    Else
    Return StringChunk.Length
    End If
    End Get
    End Property

    Public Shared ReadOnly Property BeginningOfStringFieldNumber() As String
    Get
    Return _beginningOfStringFieldNumber
    End Get
    End Property

    #End Region

    #Region "Comparison"

    Public Function CompareTo(ByVal other As StringChunkField) As Integer Implements IComparable(Of StringChunkField).CompareTo
    Return Number.CompareTo(other.Number)
    End Function

    Function IsFollowedBy(ByVal other As StringChunkField) As Object
    Return other.Number = Number + 1
    End Function

    #End Region

    #Region "Testing"

    Public Function HoldsBeginingOfTheString() As Boolean
    Return Number = 1
    End Function

    Public Shared Function IsPrefixField(ByVal field As FieldInfo) As Boolean
    Return field.Name.StartsWith(_namePrefix)
    End Function

    #End Region

    Private Function ExtractFieldNumber(ByVal fieldName As String) As Integer
    Dim fieldNumber As String = fieldName.Replace(_namePrefix, String.Empty)
    Return Integer.Parse(fieldNumber)
    End Function
    End Class

现在,我们已经定义了什么是StringChunkField使用以及如何构建之一,我们可以查询的对象时,它包含了与实例的字符串,什么名字前缀TypeEmbeddedStringReader类。

它的职责是:

  • 找到所有的StringChunkFields呈现在一个对象
  • 验证字段的编号是否发现根据在定义的基开始StringChunkField和数字是否连续
  • 重建嵌入字符串中从对象StringChunkField价值观

    Imports System.Reflection
    Imports System.Text

    Public Class TypeEmbeddedStringReader

    Public Shared Function ReadStringFrom(ByRef target As Object) As String
    ' Get all prefix fields from target
    ' Each StringChunkField hold a chunk of the String to rebuild
    Dim prefixFields As IEnumerable(Of StringChunkField) = GetPrefixFieldsFrom(target)

    ' There must be, at least, one StringChunkField
    ValidateFieldsFound(prefixFields)
    ' The first StringChunkField must hold the beggining of the string (be numbered as one)
    ValidateFieldNumbersBeginAtOne(prefixFields)
    ' Ensure that no StringChunkField number were skipped
    ValidateFieldNumbersAreConsecutive(prefixFields)

    ' Calculate the total number of chars of the string to rebuild to initialize StringBuilder and make it more efficient
    Dim totalChars As Integer = CalculateTotalNumberOfCharsIn(prefixFields)
    Dim result As StringBuilder = New StringBuilder(totalChars)

    ' Rebuild the string
    For Each field In prefixFields
    result.Append(field.StringChunk)
    Next

    ' We're done
    Return result.ToString()
    End Function

    #Region "Validation"

    Private Shared Sub ValidateFieldsFound(ByVal fields As List(Of StringChunkField))
    If (fields.Count = 0) Then Throw New ArgumentException("Does not contains any StringChunkField", "target")
    End Sub

    Private Shared Sub ValidateFieldNumbersBeginAtOne(ByVal fields As List(Of StringChunkField))
    ' Get the first StringChunkField found
    Dim firstStringChunkField As StringChunkField = fields.First

    ' If does not holds the begining of the string...
    If (firstStringChunkField.HoldsBeginingOfTheString() = False) Then
    ' Throw an exception with a meaningful error message
    Dim invalidFirstPrefixField = String.Format("The first StringChunkField found, '{0}', does not holds the beggining of the string. If holds the beggining of the string, it should be numbered as '{1}'.", firstStringChunkField.Name, StringChunkField.BeginningOfStringFieldNumber)
    Throw New ArgumentException(invalidFirstPrefixField, "target")
    End If
    End Sub

    Private Shared Sub ValidateFieldNumbersAreConsecutive(ByVal fields As List(Of StringChunkField))
    For index = 0 To fields.Count - 2
    ' Get the current and next field in fields
    Dim currentField As StringChunkField = fields(index)
    Dim nextField As StringChunkField = fields(index + 1)

    ' If the numbers are consecutive, continue checking
    If (currentField.IsFollowedBy(nextField)) Then Continue For

    ' If not, throw an exception with a meaningful error message
    Dim missingFieldMessage As String = String.Format("At least one StringChunkField between '{0}' and '{1}' is missing", currentField.Name, nextField.Name)
    Throw New ArgumentException(missingFieldMessage, "target")
    Next
    End Sub

    #End Region

    Private Shared Function CalculateTotalNumberOfCharsIn(ByVal fields As IEnumerable(Of StringChunkField)) As Integer
    Return fields.Sum(Function(field) field.NumberOfCharacters)
    End Function

    Private Shared Function GetPrefixFieldsFrom(ByVal target As Object) As List(Of StringChunkField)
    ' Find all fields int the target object
    Dim fields As FieldInfo() = target.GetType().GetFields()
    ' Select the ones that are PrefixFields
    Dim prefixFields As IEnumerable(Of StringChunkField) = From field In fields Where StringChunkField.IsPrefixField(field) Select New StringChunkField(field, target)
    ' Return the sorted list of StringChunkField found
    Return prefixFields.OrderBy(Function(field) field).ToList()

    End Function
    End Class

用法

我制备了一些样品类型测试的行为TypeEmbeddedStringReader类和使用的方式。 简单地说,你要调用的Shared功能ReadStringFrom传递作为参数包含字符串从读取对象。

以下是样本类型:

Public Class SampleType
Public Prefix_1 As String = "1 to 100 bytes"
Public Prefix_2 As String = "101 to 200 bytes"
Public Prefix_3 As String = "201 to 300 bytes"
Public Prefix_4 As String = "301 to 400 bytes"
End Class

Public Class TypeWithoutString

End Class

Public Class TypeWithNonConsecutiveFields
Public Prefix_1 As String = "1 to 100 bytes"
Public Prefix_5 As String = "101 to 200 bytes"
End Class

Public Class TypeWithInvalidStringBeginning
Public Prefix_2 As String = "1 to 100 bytes"
End Class

下面是我用来测试它的主要模块:

Imports TypeEmbeddedStringReader.Samples

Module Module1
Sub Main()
ExtractStringFrom(New TypeWithoutString())
ExtractStringFrom(New TypeWithInvalidStringBeginning())
ExtractStringFrom(New TypeWithNonConsecutiveFields())
ExtractStringFrom(New SampleType())
End Sub

Private Sub ExtractStringFrom(ByVal target As Object)
Try
Dim result As String = TypeEmbeddedStringReader.ReadStringFrom(target)
Console.WriteLine(result)
Catch exception As ArgumentException
Console.WriteLine("Type '{0}': {1}", target.GetType(), exception.Message)
End Try
Console.WriteLine()
End Sub
End Module

而从运行它的结果:

Type 'TypeEmbeddedStringReader.Samples.TypeWithoutString': Does not contains any StringChunkField
Parameter name: target

Type 'TypeEmbeddedStringReader.Samples.TypeWithInvalidStringBeginning': The first StringChunkField found, 'Prefix_2', does not holds the beggining of the string. If holds the beggining of the string, it should be numbered as '1'.
Parameter name: target

Type 'TypeEmbeddedStringReader.Samples.TypeWithNonConsecutiveFields': At least one StringChunkField between 'Prefix_1' and 'Prefix_5' is missing
Parameter name: target

1 to 100 bytes101 to 200 bytes201 to 300 bytes301 to 400 bytes

请让我知道,如果为你工作,如果我可以是任何其他帮助你。

更新

由于所要求的一族,我加入一个函数TypeEmbeddedStringReader类来读取从类型的实例的字符串提供它的名字和装配文件:

Public Shared Function ReadStringFromInstanceOf(ByRef assemblyFile As String, ByRef targetTypeName As String)
Dim assembly As Assembly = assembly.LoadFrom(assemblyFile)
Dim targetType As Type = assembly.GetType(targetTypeName)

Dim target As Object = Activator.CreateInstance(targetType)

Return ReadStringFrom(target)
End Function

下面是我用于测试的样本类型:

Public Class UnorderedFields
Public Prefix_2 As String = "101 to 200 bytes"
Public Prefix_4 As String = "301 to 400 bytes"
Public Prefix_1 As String = "1 to 100 bytes"
Public Prefix_3 As String = "201 to 300 bytes"
End Class

下面是测试它的代码:

Dim assemblyFile As String = Assembly.GetExecutingAssembly()
Dim targetTypeName As String = "TypeEmbeddedStringDemo.UnorderedFields"
Console.WriteLine(TypeEmbeddedStringReader.ReadStringFromInstanceOf(assemblyFile, targetTypeName))

这是从上述代码的输出:

1 to 100 bytes101 to 200 bytes201 to 300 bytes301 to 400 bytes

我希望这有助于你解决你的问题。 请告诉我,如果你需要什么!

更新2

回答到一族,为什么西蒙的解决方案是不工作的原因是因为比较正的字段名完成。 下面的例子在其排序失败(只是为了显示的排序问题,此外它是无效的)

Public Class UnorderedFields
Public Prefix_2 As String = "101 to 200 bytes"
Public Prefix_11 As String = "301 to 400 bytes"
Public Prefix_1 As String = "1 to 100 bytes"
Public Prefix_3 As String = "201 to 300 bytes"
End Class

它给:

1 to 100 bytes**301 to 400 bytes**101 to 200 bytes201 to 300 bytes

固定比较器的实现使用数字而不是名称:

Public Function Compare(ByVal x As FieldInfo, ByVal y As FieldInfo) As Integer Implements IComparer(Of FieldInfo).Compare
Dim xNumber = Integer.Parse(x.Name.Replace("Prefix_", String.Empty))
Dim yNumber = Integer.Parse(y.Name.Replace("Prefix_", String.Empty))
Return xNumber.CompareTo(yNumber)
End Function

给出正确的结果:

1 to 100 bytes101 to 200 bytes201 to 300 bytes301 to 400 bytes

希望它帮助。

你有公共领域如此,从Type对象代表类获得FieldInfo对象,并排除那些名不启动Prefix_

一旦你拥有了这些,你就可以调用GetValueFieldInfo与对象(类的实例对象Test )作为参数,以获得字段的值。

如果您需要订购反正结果,那么我建议一个LINQ声明

对不起,我不知道VB否则我会写信给你一些代码。

更新:一些C#代码

Test myTestInstance = ... // Do stuff to the the instance of your class
Type myType = typeof(Test); // Or call GetType() on an instance
FieldInfo[] myFields = myType.GetFields();
var myPrefixedFields = myFields
.Where(fi => fi.Name.StartsWith("Prefix_"))
.OrderBy(fi => fi.Name);
string result = string.Empty;
foreach(FieldInfo fi in myPrefixedFields)
{
// You may prefer to use a string builder.
result += fi.GetValue(myTestInstance);
}

这应该是它。

得到它在C#代码(VB.NET是有点生疏了:)):

using System;
using System.Linq;
using System.Text;
using System.Reflection;

void ExtractFields()
{
const string prefix = "Prefix_";
Assembly assembly = Assembly.LoadFile("C:\\Test.dll");
Type classTestType = assembly.GetType("Test");
var classTest = Activator.CreateInstance(classTestType);
FieldInfo[] fields = classTestType.GetFields(BindingFlags.GetField)
.Where(m => m.Name.StartsWith(prefix))
.OrderBy(m => m.Name)
.ToArray();
var sb = new StringBuilder();
foreach (FieldInfo field in fields)
{
sb.Append(field.GetValue(classTest));
}
string allStringConcatenated = sb.ToString();
}

使用测试类,稍加修改,从你的问题:

Public Class Test
Public Prefix_15 As String = "501 to 600 bytes"
Public Prefix_5 As String = "401 to 500 bytes"
Public Prefix_1 As String = "1 to 100 bytes"
Public Prefix_2 As String = "101 to 200 bytes"
Public Prefix_3 As String = "201 to 300 bytes"
Public Prefix_4 As String = "301 to 400 bytes"
End Class

运行以下功能:

Public Function GetPrefixString() As String
Dim type As Type = Assembly.LoadFrom("C:\test.dll").GetType("Test.Test")
Dim test As Object = Activator.CreateInstance(type)

Dim fieldList As New List(Of String)
For Each field As FieldInfo In _
From x In type.GetFields _
Where x.Name.StartsWith("Prefix_") _
Order By Convert.ToInt32(x.Name.Replace("Prefix_", String.Empty))
fieldList.Add(field.GetValue(test))
Next

Return String.Join(String.Empty, fieldList.ToArray)
End Sub

得到以下的结果:

1-100 bytes101至200 bytes201至300 bytes301至400 bytes401至500 bytes501到600字节

分类:。净 时间:2015-03-16 人气:3
本文关键词: .NET,串,vb.net
分享到:

相关文章

Copyright (C) 55228885.com, All Rights Reserved.

55228885 版权所有 京ICP备15002868号

processed in 0.452 (s). 10 q(s)