如何支持多种自定义类型?

时间:2012-10-17 20:41:25

标签: c#

我有一个Types项目,我在其中定义了我想在我的主应用程序中处理的自定义类对象。对象基本上是从字符串派生并解析成结构的。

我有两个问题

1 - 在一个单独的项目中,我有一个文件阅读器类,我在其中扫描文本文件以查找我定义的字符串类型。例如通过正则表达式。目前我添加了我的Types项目作为项目引用,我只列出了我读类顶部的正则表达式。当我找到一个类型我将字符串转换为适当的类型。但是,我如何才能改进这一点,以便它直接连接到我的Types项目 - 所以当我用新类型更新它时,Read类知道它应该支持新的类型?

2 - 我正在尝试创建一个在从文本文件中读取后对这些特定类型起作用的DLL。如何告诉我的DLL我想支持我的Types项目中的类型?我是否必须为我想要处理的每种类型创建一个重载函数?我是否使用界面?

非常感谢任何建议。

编辑:添加了我正在尝试做的示例代码

// PROJECT 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

} 

//项目4 - 带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);
            }
        }
    }
}

2 个答案:

答案 0 :(得分:6)

您应该使用接口,然后使所有类型实现接口。在这之后,你应该改变你的Read类来操作界面而不是单个类。

这样您可以根据需要添加任意数量的类型,而不必更新Read类。

答案 1 :(得分:1)

我希望我能正确理解你。

您在Type项目中创建的类表示一些具有不同行为但具有相同数据成员的对象,并且您希望能够在项目中轻松使用这些对象,而无需显式列出这些对象。

我会创建一些基本接口,我可以在Types项目中实现所有对象。 然后,我将使用一个Factory类,它将使用反射来收集实现所述接口的所有对象。

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类中,多态性将确切地处理将要调用的转换。

我会使用RegularExpression来检测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));