2012-10-17 51 views
6

我有一個類型項目,我定義自定義類對象,我想在我的主應用程序中工作。這些對象基本上是從字符串派生出來的,並被解析成一個結構體如何支持多種自定義類型?

我有兩個問題

1 - 在一個單獨的項目,我有一個文件讀取器類,我掃描的文本文件我已經定義字符串類型。例如通過正則表達式。目前,我將我的類型項目添加爲項目引用,並且只在正常閱讀類的頂部列出正則表達式。當我找到一個類型,我將字符串轉換爲適當的類型。然而,我怎麼能改善這個,這是它直接連接到我的類型項目 - 所以當我用新類型更新它的Read類知道它應該支持新類型?

2 - 我試圖從文本文件中讀取後創建一個在這些特定類型上工作的DLL。我如何告訴我的DLL,我想支持我的類型項目中的類型?我是否必須爲每個想要處理的類型創建一個重載函數?我使用界面嗎?

任何意見非常感謝。

編輯:加什麼I''m試圖做的示例代碼

//項目1 - 處理IO操作,如閱讀和寫作在讀類工作
//功能是找到一個多個預定義的字符串類型由正則表達式...一旦發現它們被轉換爲所述數據結構(通過傳遞字符串中的其他項目中定義類型的類構造函數

public class Read 
{ 
    public string[] FileList { get; set; } 

    private static Int64 endOffset = 0; 
    private FileStream readStream; 
    private StreamReader sr; 

    private System.Text.RegularExpressions.Regex type1 = new System.Text.RegularExpressions.Regex(@"@123:test"); 
    private System.Text.RegularExpressions.Regex type2 = new System.Text.RegularExpressions.Regex(@"TESTTYPE2"); 

    public Read(string[] fl) 
    { 
     FileList = fl; 
    } 

    public object ReturnMessage(FileStream readStream, out int x) 
    { 
     //readStream = new FileStream(file, FileMode.Open, FileAccess.Read); 
     x = 0; 
     //endOffset = 0; 
     bool found = false; 
     char ch; 
     string line = string.Empty; 

     object message = null; 

     while (!(x < 0)) //do this while not end of line (x = -1) 
     { 
      readStream.Position = endOffset; 

      //line reader 
      while (found == false) //keep reading characters until end of line found 
      { 
       x = readStream.ReadByte(); 
       if (x < 0) 
       { 
        found = true; 
        break; 
       } 
       // else if ((x == 10) || (x == 13)) 
       if ((x == 10) || (x == 13)) 
       { 
        ch = System.Convert.ToChar(x); 
        line = line + ch; 
        x = readStream.ReadByte(); 
        if ((x == 10) || (x == 13)) 
        { 
         ch = System.Convert.ToChar(x); 
         line = line + ch; 
         found = true; 
        } 
        else 
        { 
         if (x != 10 && (x != 13)) 
         { 
          readStream.Position--; 
         } 
         found = true; 
        } 
       } 
       else 
       { 
        ch = System.Convert.ToChar(x); 
        line = line + ch; 
       } 
      }//while - end line reader 



      //examine line (is it one of the supported types?) 
      if (type1.IsMatch(line)) 
      { 
       message = line; 
       endOffset = readStream.Position; 

       break; 
      } 
      else 
      { 
       endOffset = readStream.Position; 
       found = false; 
       line = string.Empty; 
      } 

     }//while not end of line 


     return message; 
    } 

} 

// PROJECT 2 - 包含定義的類類型

// TYPE1

namespace MessageTypes.Type1 
{ 
public sealed class Type1 
{ 
    public List<Part> S2 { get; set; } 

    public Type1(string s) 
    { 
     S2 = new List<Part>(); 
     string[] parts = s.Split(':'); 
     for (int i = 0; i < parts.Length; i++) 
     { 
      S2.Add(new Part(parts[i])); 
     } 
    } 
} 

public sealed class Part 
{ 
    public string P { get; set; } 

    public Part(string s) 
    { 
     P = s; 
    } 
} 
} 

// TYPE 2

namespace MessageTypes.Type2 
{ 
public sealed class FullString 
{ 
    public string FS { get; set; } 

    public FullString(string s) 
    { 
     FS = s; 
    } 
} 
} 

// PROJECT 3

class DoSomethingToTypeObject{ 

//detect type and call appropriate function to process 

} 

// PROJECT 4 - MAIN PROJECT與GUI

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 
    private void button1_Click(object sender, RoutedEventArgs e) 
    { 
     if (tabControl1.SelectedIndex == 0) //Processing Mode 1 
     { 
      //load file list from main window - Mode1 tab 
      IOHandler.Read read = new IOHandler.Read(new string[2] { @"C:\file1.txt", @"C:\file2.txt" }); 

      //read files 
      foreach (string file in read.FileList) 
      { 

       //while not end of stream 
       myobject = read.ProcessFile(file); 

       DoSomethingtoTypeObject DS = new DoSomethingtoTypeObject(myobject); 

       //write transoformed object 
       write(myobject); 
      } 
     } 
    } 
} 

回答

1

我希望我能正確理解你。

您在Type項目中創建的類表示一些具有不同行爲但數據成員相同的對象,並且希望能夠在項目中輕鬆使用這些對象,而不必顯式列出這些對象。

我會創建一些基本接口,以便在類型項目中實現所有對象。 然後,我會使用一個工廠類,它將使用反射來收集所有實現上述接口的對象。

public interface iFoo 
{ 
    string FoundItem { get; set; } 
    string Expression { get; } 
    string Value { get; set; } 
    void sharedFunctionName(); 
} 

public static class FooFactory 
{ 
    public static List<iFoo> GetTypeList() 
    { 
     List<iFoo> types = new List<iFoo>(); 
     types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies() 
         from t in assembly.GetTypes() 
         where t.IsClass && t.GetInterfaces().Contains(typeof(iFoo)) 
         select Activator.CreateInstance(t) as iFoo); 

     return types; 
    } 
} 

然後,您的讀者將收到支持類型的所有必要信息,而不必手動指定它。

因爲我想值類型會在某個點是不同的,你可以使用一個通用接口是這樣的:

public interface iFoo 
{ 
    string FoundItem { get; set; } 
    string Expression { get; } 
    void sharedFunctionName(); 
} 

public interface iFoo<T> : iFoo 
{ 
    T Value { get; set; } 
} 

public static class FooFactory 
{ 
    public static List<iFoo> GetTypeList() 
    { 
     List<iFoo> types = new List<iFoo>(); 
     types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies() 
         from t in assembly.GetTypes() 
         where t.IsClass && t.GetInterfaces().Contains(typeof(iFoo)) 
         select Activator.CreateInstance(t) as iFoo); 

     return types; 
    } 
} 

public class FooBar : iFoo<int> 
{ 

} 

在這個例子中的基本接口IFoo的保持緩和發現過程。 使用泛型接口將允許保持您的代碼類型安全(而不是使用類型對象的值),但在恢復對象時必須添加一些邏輯才能正確訪問您的值。

另外,如果您需要創建需要在所有對象中共享的函數,您可以在Factory Class和Voilà中添加擴展方法。

編輯:基於新的信息

你的類型對應於一個類型的數據,您將基於一些正則表達式文件中找到。 根據用戶選擇和類型可能會有不同類型的轉換。

我們知道用戶必須從列表中選擇一種模式,這會影響應用於類型的轉換。

所以這就是我要做的: 我會將轉換邏輯正確地移動到Type類中,polymophism將負責確切地調用哪個轉換。

我會把RegularExpression用來檢測Type到Type本身,這將允許你使用反射和Factory類更容易地討論。

這樣,一切都是標準的。您的讀者知道您在類型項目中創建的任何新類型,而無需手動干預,並且一旦檢測到可以應用正確的轉換並且始終可以訪問原始字符串。

public enum UserMode {Mode1, Mode2}; 

public interface iType 
{ 
    string Expression {get;} 
    string OriginalString {get; set;} 
    string Transform(UserMode Mode); 
    iType getNewInstance(string OriginalString); 

} 

public class Type1 : iType 
{ 
    public string Expression {get { return "RegularExpression"; }} 
    public string OriginalString {get; set;} 
    //Add any other private members you need to accomplish your work here. 
    public string Transform(UserMode Mode) 
    { 
     switch(Mode) 
     { 
     case UserMode.Mode1: 
      //write the transformation code for this scenario 
      return ResultString; 
      break; 
     } 
    } 

    public iType getNewInstance(string Original) 
    { 
    return (iType)(new Type1(){ OriginalString = Original }); 
    } 
} 

public static class TypeFactory 
{ 
    public static List<iType> GetTypeList() 
    { 
     List<iType> types = new List<iType>(); 
     types.AddRange(from assembly in AppDomain.CurrentDomain.GetAssemblies() 
         from t in assembly.GetTypes() 
         where t.IsClass && t.GetInterfaces().Contains(typeof(iType)) 
         select Activator.CreateInstance(t) as iType); 

     return types; 
    } 
} 

現在,如果匹配列表中的iTypes表達式,您將需要做的所有事情。 當你有一個匹配你這樣做:

var TransformationReady = from t in TypeFactory.GetTypeList() 
          where Regex.IsMatch(YourFileLine, t.Expression) 
          select t.getNewInstance(Regex.Match(YourFileLine, t.Expression)); 
+0

我會試試這個。我用我想要做的事情的示例代碼更新了我的原始帖子。請看看它是否會改變您的任何建議。我不確定這個**字符串FoundItem {get;組; } string Expression {get; }'**在界面中。什麼是Founditem和表達式(匹配和正則表達式?)。對我來說,當我找到它的時候,它是一個字符串,但稍後它會轉換爲數據結構。這很重要嗎? – sjs

+0

FoundItem和Expression只是在接口中的成員的例子,並不一定要在那裏。 我在看你提供的代碼,你只是使用基於類型的特定轉換的結果,還是你需要使用這個結構,因爲它以後呢? –

+0

我的DoSomethingClass會修改對象內部的字符串。例如,說我的字符串對象表示一個CSV文件中的一行。也許我需要用特定值替換第三列。在這種情況下,我需要返回相同的結構,以便寫入函數可以訪問組成該行的所有值。 DoSomthing的每個實現(每個類型)將保持結構完整。我可能有其他模式(DoSomething2)使用該對象,但執行不同的功能,如檢索值。只有Write類將輸出一個字符串,因爲它最初是在文件中。 – sjs

6

您應該使用一個接口,然後讓所有類型實現接口。做完這些之後,你應該改變你的Read類來在接口上運行而不是單獨的類。

通過這種方式,您可以添加儘可能多的類型,而無需更新Read類。

+1

如果你知道時間提前哪種類型你期待下一個讀這隻會工作。 –

+0

你確定嗎?只要他使用他現在使用的接口和他的類,並在將來添加接口的實現? – mattytommo

+1

實現必須知道所有類型的檢測目的。這對我來說似乎沒有太多的SRP。雖然,我想你可以用某種工廠對象註冊實現接口的類型。 –