How to support multiple custom types?

I have a Types project in which I define custom class objects that I want to work on in my main application. Objects are basically inferred from strings and parsed into a structure.

I have two problems:

1 - In a separate project, I have a file reader class where I look at text files for the line types that I defined. For example, by regular expression. Currently, I have added the Types project as a reference to the project, and I just listed the regular expressions at the top of my reading class. When I find a type, I convert the string to the corresponding type. However, how can I improve this so that it is directly related to my Types project - so when I update it with new types, the reading class knows that it needs to support new types?

2 - I am trying to create a DLL that works on these specific types after reading them from a text file. How do I tell my DLL that I want to support types in a Types project? Do I have to perform an overloaded function for each type that I want to work on? Am I using an interface?

Any advice is appreciated.

EDIT : Added sample code of what I'm trying to do

// PROJECT 1 - handles an input-output operation, for example, reading and writing
// the function in the class read job is to find one of several predefined string types with a regular expression ... as soon as they are converted to a data structure (by passing the string to the constructor of the type class defined in another project

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 - contains classes that define types

// 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 - THE MAIN PROJECT with a graphical interface

  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); } } } } 
+6
source share
2 answers

I hope I understand you correctly.

The class that you create in the type project consists of several objects that have different types of behavior, but the same data elements, and you would like to be able to easily use them in your projects without the hassle of explicitly listing these objects.

I would create some basic interface that implements all my objects in the Types project. Then I used the Factory class, which would use reflection to collect all objects that implement the specified interface.

 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; } } 

Then your Reader will receive all the necessary information for the supported types, if you do not have to manually quote it.

Since I assume that the type of the value will be different at some point, you can use the general interface as follows:

 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> { } 

In this example, the basic iFoo interface is supported to facilitate the discovery process. Using a universal interface would keep the type code safe (as opposed to using the type type value), but you will have to add some logic when restoring your objects in order to be able to properly access your value.

In addition, if you ever need to create functions that require sharing within all of your objects, you can add extension methods in the Factory and VoilΓ  class.

EDIT:

Based on new information:

Your types correspond to the type of data that you find in the file based on some regular expression. There may be another type of conversion based on user choice and type.

We know that the user will need to select a mode from the list, and this will affect the conversion applied to types.

So here is what I will do: I would move the conversion logic directly to the Type class, the polymofit will take care of which conversion will be called.

I would put RegularExpression to define the type in the type itself, this will allow you to use reflection and discussion of the Factory class more efficiently.

Thus, everything is standard. Your reader knows about any new type that you create in the type project without manual intervention, and once the correct conversion is found, you can apply, and the source string is always available.

 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; } } 

Now, all you will need to do is if the matching expression from iTypes is listed. When you play a match, follow these steps:

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

You must use an interface and then use all of your interface types. After that, you must change the reading class to work with the interface of NOT individual classes.

This way you can add as many types as you want and do not have to update the reading class.

+6
source

Source: https://habr.com/ru/post/927976/


All Articles