How to rewrite a Java recursive service to .Net 5? - c#

I have Java service what creates Menu tree with all children. It works perfectly for Menu.
I want to rewrite with .Net5 but it's difficult for me.
// Java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Stream;
public class AdminNode implements Iterable<Resource>
{
private Resource resource;
private List<AdminNode> children;
public List<AdminNode> getChildren() {
return children;
}
public AdminNode(Resource resource)
{
this.resource = resource;
this.children = new ArrayList<>();
}
public void addResource(Resource resource)
{
String[] pathArr = resource.getPath().split("-");
List<Integer> intArray = new ArrayList<Integer>();
for(int i = 0; i < pathArr.length; i++) {
intArray.add(Integer.parseInt(pathArr[i]));
}
addResource(resource, intArray);
}
private void addResource(Resource resource, List<Integer> path)
{
if (path.size() > 1)
{
Integer nextParent = path.get(0);
path.remove(0);
for (AdminNode child : children)
{
if (child.getResource().getId().equals(nextParent))
{
child.addResource(resource, path);
}
}
}
else
{
children.add(new AdminNode(resource));
}
}
public Resource getResource() { return resource; }
#Override
public Iterator<Resource> iterator()
{
return stream().iterator();
}
public Stream<Resource> stream()
{
return goDown(this).skip(1).map(AdminNode::getResource);
}
private static Stream<AdminNode> goDown(AdminNode node)
{
Stream<AdminNode> result = Stream.concat(Stream.of(node), node.children.stream().flatMap(AdminNode::goDown));
return result;
}
#Override
public String toString() {
return "AdminNode [resource=" + resource + ", children=" + children + "]";
}
}
I think class can to be:
// C#
public class AdminNode : IEnumerable<Resource> {
private Resource _resource;
private List<AdminNode> _children;
public List<AdminNode> getChildren() {
return _children;
}
public AdminNode(Resource resource)
{
_resource = resource;
_children = new List<>();
}
public void addResource(Resource resource)
{
var pathArr = _resource.Path.Split("-");
var intArray = new List<int>();
for(int i = 0; i < pathArr.Length; i++) {
intArray.Add(Convert.ToInt32(pathArr[i]));
}
addResource(resource, intArray);
}
private void AddResource(Resource resource, List<int> path)
{
if (path.Count > 1)
{
var nextParent = path[0];
path.Remove(0);
foreach (void child in _children)
{
if (child.GetResource().Id == nextParent)
{
child.AddResource(resource, path);
}
}
}
else
{
_children.Add(new AdminNode(resource));
}
}
public Resource GetResource() { return _resource; }
public IEnumerator<Resource> GetEnumerator()
{
//?
}
IEnumerator IEnumerable.GetEnumerator()
{
// ?
}
// and there I stopped.
}
.Net5 does not has Stream, flatMap. Maybe FlatMap I can change with Linq SelectMany.
I don't understand three methods:
stream()
goDown().
How to convert these methods to .Net5?

From a brief glance at Stream in Java, it looks like that is basically their implementation of IEnumerable<T> and LINQ in C#. Essentially it is a toolset to do lazy evaluations over collections. Below is my best guess of what you are needing in C#
public class AdminNode : IEnumerable<Resource>
{
private List<AdminNode> _children = new List<AdminNode>();
public AdminNode(Resource resource)
{
Resource = resource;
}
public Resource Resource { get; }
public IEnumerable<AdminNode> GoDown()
{
var stack = new Stack<AdminNode>();
//this could be done recursively, but explicitly implementing with a stack
//reduces the risk of a stack overflow exception with large trees
stack.Push(this);
while(stack.Any())
{
var next = stack.Pop();
yield return next;
foreach(var child in next._children)
{
stack.Push(child);
}
}
}
public IEnumerator<Resource> GetEnumerator() { return GoDown().Select(x => x.Resource).GetEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return GoDown().Select(x => x.Resource).GetEnumerator(); }
}
In this implementation, GoDown() should return an IEnumerable<AdminNode> of all the AdminNodes starting at the current AdminNode and all nodes below it.
If you enumerate an AdminNode it will enumerate over all resources starting at the current node, and then all resources of children below that node.

Related

Implementing interface with class members and functions that need access to them in C#

I have this class:
public class Node
{
public int Data;
public Node Next;
}
and this interface:
public interface IMyList
{
Node Head { get; set; }
void Add(int elm); // add new element
void PrintAll(); //print all list
void Reverse(); // reverse list, implement without using helpers collection\arrays
}
and I need to implement the interface to use all it's inner functions
this is my class that implements the interface:
public class MyCustomizedList : IMyList
{
Node IMyList.Head { get; set ; }
public void Add(int elm) { /*something goes here*/ } // add new element
public void PrintAll() { /*and here*/ } //print all list
public void Reverse() { /*and also here*/ }
// reverse list, implement without using helpers collection\arrays
}
but I don't understand how do I gain access to the fields of class Node
for example If I want to Implement the function Add()
how do I set the fields of the inner Node Class to attach pointer to the Next Node and the elm value to it's data?
Right now, you are implementing the property Head explicitly:
Node IMyList.Head { get; set ; }
To access it, the left hand side of the . must be IList. One simple way to do that is ((IList)this).Head.
For example, to print it to the console:
Console.WriteLine(((IList)this)Head);
Alternatively, if there is no reason for you to implement Head explicitly, don't. Implement it implicitly instead, just like the other members:
public Node Head { get; set; }
Try this:
public class MyCustomizedList : IMyList
{
public Node Head { get; set; }
public void Add(int elm)
{
var newNode = new Node { Data = elm };
if (this.Head == null)
{
this.Head = newNode;
}
else
{
var node = this.Head;
while (node.Next != null)
{
node = node.Next;
}
node.Next = newNode;
}
}
public void PrintAll()
{
var builder = new StringBuilder();
var node = this.Head;
while (node.Next != null)
{
builder.AppendLine(node.Data.ToString());
node = node.Next;
}
var text = builder.ToString();
Console.WriteLine(text);
}
public void Reverse()
{
if (this.Head?.Next != null)
{
var node = this.Head;
this.Head = Reverse(node, node.Next);
node.Next = null;
}
}
private static Node Reverse(Node node1, Node node2)
{
if (node2.Next != null)
{
var lastNode = Reverse(node2, node2.Next);
node2.Next = node1;
return lastNode;
}
node2.Next = node1;
return node2;
}
}
I think isn't not an efficient data structure. What is the purpose of this class?
To Add an item you must iterate all elements.
You haven't any remove method.
Head is public and their properties too: is not protected from outside mistakes, is not encapsulated...

C# method Linq variable return

hope your help :)
I search to make the result of the LinQ Variable bellow "ES" available in an other method.
public void Contract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
I downloaded QuantConnect just to get an idea what you're trying to do. The example below should at least not yield any errors, but I haven't tried the output.
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public interface IFuturesContractSelector_ES
{
FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public FuturesContract GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
}
Or you could do an extension on the Slice class:
using QuantConnect.Data;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Algorithm
{
public static class SliceExtensions
{
public static FuturesContract GetFuturesContract_ES(this Slice slice, QCAlgorithm Algorithm_ES)
{
foreach (var chain in slice.FutureChains)
{
if (chain.Value.Symbol.Value.StartsWith("ES"))
{
return (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return null;
}
}
public class Test
{
public void TestMyMethod(Slice slice)
{
var contract = slice.GetFuturesContract_ES(new QCAlgorithm());
//... do something
}
}
}
I tried to create an interface then the method, result is :
using QuantConnect.Securities;
namespace Quant
{
public interface IFuturesContractSelector_ES
{
void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice);
}
}
public class Contract_ES : IFuturesContractSelector_ES
{
private readonly Slice _Slice;
private readonly QCAlgorithm _Algorithm_ES;
public Contract_ES(QCAlgorithm Algorithm_ES)
{
_Algorithm_ES = Algorithm_ES;
}
public Contract_ES(Slice slice)
{
_Slice = slice;
}
public void GetFuturesContract_ES(QCAlgorithm Algorithm_ES, Slice slice)
{
foreach(var chain in slice.FutureChains)
{
if (chain.Value.Symbol.StartsWith("ES"))
{
var ES = (from futuresContract in chain.Value.OrderBy(x => x.Expiry)
where futuresContract.Expiry > Algorithm_ES.Time.Date.AddDays(1)
select futuresContract).FirstOrDefault();
}
}
return ES;
}
}
At the Line return ES, I get this error :
The name "ES" does not exist in the current context.
Weird because I have another method build in this way, with no prob -_-
Maybe using foreach statement that cause the non possible return of "var ES" ?

Need help in understanding the below .NET code

This is a basically a class library project which is somehow exposed as a WCF service. The code below is a part of the Data Access Layer. 'db' is an object of a DataContext class. To save a file, we do the following-
public static Guid SaveFile(FileDetails fileDetails)
{
System.Nullable<Guid> id = null;
SystemDataContext.UsingWrite(db =>
{
db.SaveFileData(fileDetails.RunId, fileDetails.FileData, fileDetails.FileExtension, ref id);
});
return id ?? Guid.Empty;
}
Then, the below would execute-
public static void UsingWrite(Action<SoftCashCreditDBDataContext> action)
{
using (var context = new SystemDataContext())
{
try
{
action(context.Write);
}
catch (Exception ex)
{
DataAccessExceptionHandler.HandleExcetion(ex, Config.DataLayerPolicy);
}
}
}
public SystemDataContext()
{
if (_stack == null)
{
_stack = new Stack<SystemDataContext>();
this.Depth = 1;
this.Read = new SoftCashCreditDBDataContext(Config.ReadDatabaseConnection);
this.Write = new SoftCashCreditDBDataContext(Config.WriteDatabaseConnection);
}
else
{
var parent = _stack.Peek();
/// Increment level of node.
this.Depth = parent.Depth + 1;
/// Copy data context from the parent
this.Read = parent.Read;
this.Write = parent.Write;
}
_stack.Push(this);
}
public int Depth { get; private set; }
public bool IsRoot { get { return this.Depth == 1; } }
[ThreadStatic]
private static Stack<SystemDataContext> _stack = null;
public SoftCashCreditDBDataContext Read { get; private set; }
public SoftCashCreditDBDataContext Write { get; private set; }
#region IDisposable Members
public void Dispose()
{
var context = _stack.Pop();
if (context.IsRoot == true)
{
context.Read.Dispose();
context.Write.Dispose();
_stack = null;
}
}
#endregion
}
They have implemented LINQ to SQL here, and created a DBContext class. The 'SaveFileData()' method is actually part of that class, where it just calls an SP inside to save the file.
What I did not follow-
What exactly does the call to UsingWrite() do here? What is passed to the 'Action action' parameter, and what is it doing?
I understand your confusion. They use 2 delegates.
This is passed to the action parameter:
db =>
{
db.SaveFileData(fileDetails.RunId, fileDetails.FileData, fileDetails.FileExtension, ref id);
}
So when UsingWrite is called, the SoftCashCreditDBDataContext delegate which was set in the Write delegate will call SaveFileData.
A simplified example to help you understand Action:
public void Main()
{
Test(x => Debug.Write(x));
}
private void Test(Action<string> testAction)
{
testAction("Bla");
}
This function will call Debug.Write with the argument x, which is a string that is passed to the test action function.

.Net 2.0 Searching for member Object in a generic list

I am using.Net 2.0
I have a generic
List< MyContainerObject > MyList;
and
MyContainerClass MyContainerObject = new MyContainerClass();
and
Public Class MyContainerClass
{
public BasicClass BasicObject;
public AdvanceClass AdvanceObject
}
How can I search for BasicObject in MyList efficiently?
Sample Code added
namespace WindowsApplication4
{
public class Program
{
private List<ContainerClass> MyList;
public Program()
{
MyList = new List<ContainerClass>();
}
private void Add(object sender, EventArgs e)
{
ContainerClass objContainer1 = new ContainerClass("B1","A1");
ContainerClass objContainer1 = new ContainerClass("B2", "A2");
MyList.Add(objContainer1);
MyList.Add(objContainer2);
}
private void Get(BasicClass objBasic)
{
//How to retreive ContainerClass from MyList that has objBasic ??
}
}
public class ContainerClass
{
private BasicClass BasicObject;
private AdvancedClass AdvancedObject;
public ContainerClass(string baseID, string AdvanceID)
{
BasicObject = new BasicClass();
BasicObject.ID = baseID;
AdvancedObject = new AdvancedClass();
AdvancedObject.ID = AdvanceID;
}
}
public class BasicClass
{
public string ID;
public int name;
}
public class AdvancedClass
{
public string ID;
public int name;
}
}
I think it would be very nice if you would be using .Net version higher than 2.0 than you caould use the linq to simply get the object you want rom the list.
but you can use delegate and find method
http://msdn.microsoft.com/en-us/library/x0b5b5bc.aspx
could be something like
MyContainerClass MyContainerObject = MyList.Find(delegate(MyContainerClass p) {return
BasicObject.Val == someval; });
var found = MyList.FirstOrDefault(o => o.BasicObject == someObject);
Note that unless BasicObject implement IEquatable<BasicObject> and/or overloads Equals/operator== you end up with object.ReferenceEquals(o.BasicObject, someObject) effectively.
Oops. .NET 2.0. Well:
BasicObject FindBy(List<MyContainerClass> list, BasicObject o)
{
foreach (MyContainerClass i in list)
{
if (i.BasicObject == o) // same caveats on Equality
return i;
}
return null;
}

Bridge or Factory and How

I'm trying to learn patterns and I've got a job that is screaming for a pattern, I just know it but I can't figure it out. I know the filter type is something that can be abstracted and possibly bridged. I'M NOT LOOKING FOR A CODE REWRITE JUST SUGGESTIONS. I'm not looking for someone to do my job. I would like to know how patterns could be applied to this example.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.IO;
using System.Xml;
using System.Text.RegularExpressions;
namespace CopyTool
{
class CopyJob
{
public enum FilterType
{ TextFilter, RegExFilter, NoFilter }
public FilterType JobFilterType { get; set; }
private string _jobName;
public string JobName { get { return _jobName; } set { _jobName = value; } }
private int currentIndex;
public int CurrentIndex { get { return currentIndex; } }
private DataSet ds;
public int MaxJobs { get { return ds.Tables["Job"].Rows.Count; } }
private string _filter;
public string Filter { get { return _filter; } set { _filter = value; } }
private string _fromFolder;
public string FromFolder
{
get { return _fromFolder; }
set
{
if (Directory.Exists(value))
{ _fromFolder = value; }
else
{ throw new DirectoryNotFoundException(String.Format("Folder not found: {0}", value)); }
}
}
private List<string> _toFolders;
public List<string> ToFolders { get { return _toFolders; } }
public CopyJob()
{
Initialize();
}
private void Initialize()
{
if (ds == null)
{ ds = new DataSet(); }
ds.ReadXml(Properties.Settings.Default.ConfigLocation);
LoadValues(0);
}
public void Execute()
{
ExecuteJob(FromFolder, _toFolders, Filter, JobFilterType);
}
public void ExecuteAll()
{
string OrigPath;
List<string> DestPaths;
string FilterText;
FilterType FilterWay;
foreach (DataRow rw in ds.Tables["Job"].Rows)
{
OrigPath = rw["FromFolder"].ToString();
FilterText = rw["FilterText"].ToString();
switch (rw["FilterType"].ToString())
{
case "TextFilter":
FilterWay = FilterType.TextFilter;
break;
case "RegExFilter":
FilterWay = FilterType.RegExFilter;
break;
default:
FilterWay = FilterType.NoFilter;
break;
}
DestPaths = new List<string>();
foreach (DataRow crw in rw.GetChildRows("Job_ToFolder"))
{
DestPaths.Add(crw["FolderPath"].ToString());
}
ExecuteJob(OrigPath, DestPaths, FilterText, FilterWay);
}
}
private void ExecuteJob(string OrigPath, List<string> DestPaths, string FilterText, FilterType FilterWay)
{
FileInfo[] files;
switch (FilterWay)
{
case FilterType.RegExFilter:
files = GetFilesByRegEx(new Regex(FilterText), OrigPath);
break;
case FilterType.TextFilter:
files = GetFilesByFilter(FilterText, OrigPath);
break;
default:
files = new DirectoryInfo(OrigPath).GetFiles();
break;
}
foreach (string fld in DestPaths)
{
CopyFiles(files, fld);
}
}
public void MoveToJob(int RecordNumber)
{
Save();
LoadValues(RecordNumber - 1);
}
public void AddToFolder(string folderPath)
{
if (Directory.Exists(folderPath))
{ _toFolders.Add(folderPath); }
else
{ throw new DirectoryNotFoundException(String.Format("Folder not found: {0}", folderPath)); }
}
public void DeleteToFolder(int index)
{
_toFolders.RemoveAt(index);
}
public void Save()
{
DataRow rw = ds.Tables["Job"].Rows[currentIndex];
rw["JobName"] = _jobName;
rw["FromFolder"] = _fromFolder;
rw["FilterText"] = _filter;
switch (JobFilterType)
{
case FilterType.RegExFilter:
rw["FilterType"] = "RegExFilter";
break;
case FilterType.TextFilter:
rw["FilterType"] = "TextFilter";
break;
default:
rw["FilterType"] = "NoFilter";
break;
}
DataRow[] ToFolderRows = ds.Tables["Job"].Rows[currentIndex].GetChildRows("Job_ToFolder");
for (int i = 0; i <= ToFolderRows.GetUpperBound(0); i++)
{
ToFolderRows[i].Delete();
}
foreach (string fld in _toFolders)
{
DataRow ToFolderRow = ds.Tables["ToFolder"].NewRow();
ToFolderRow["JobId"] = ds.Tables["Job"].Rows[currentIndex]["JobId"];
ToFolderRow["Job_Id"] = ds.Tables["Job"].Rows[currentIndex]["Job_Id"];
ToFolderRow["FolderPath"] = fld;
ds.Tables["ToFolder"].Rows.Add(ToFolderRow);
}
}
public void Delete()
{
ds.Tables["Job"].Rows.RemoveAt(currentIndex);
LoadValues(currentIndex++);
}
public void MoveNext()
{
Save();
currentIndex++;
LoadValues(currentIndex);
}
public void MovePrevious()
{
Save();
currentIndex--;
LoadValues(currentIndex);
}
public void MoveFirst()
{
Save();
LoadValues(0);
}
public void MoveLast()
{
Save();
LoadValues(ds.Tables["Job"].Rows.Count - 1);
}
public void CreateNew()
{
Save();
int MaxJobId = 0;
Int32.TryParse(ds.Tables["Job"].Compute("Max(JobId)", "").ToString(), out MaxJobId);
DataRow rw = ds.Tables["Job"].NewRow();
rw["JobId"] = MaxJobId + 1;
ds.Tables["Job"].Rows.Add(rw);
LoadValues(ds.Tables["Job"].Rows.IndexOf(rw));
}
public void Commit()
{
Save();
ds.WriteXml(Properties.Settings.Default.ConfigLocation);
}
private void LoadValues(int index)
{
if (index > ds.Tables["Job"].Rows.Count - 1)
{ currentIndex = ds.Tables["Job"].Rows.Count - 1; }
else if (index < 0)
{ currentIndex = 0; }
else
{ currentIndex = index; }
DataRow rw = ds.Tables["Job"].Rows[currentIndex];
_jobName = rw["JobName"].ToString();
_fromFolder = rw["FromFolder"].ToString();
_filter = rw["FilterText"].ToString();
switch (rw["FilterType"].ToString())
{
case "TextFilter":
JobFilterType = FilterType.TextFilter;
break;
case "RegExFilter":
JobFilterType = FilterType.RegExFilter;
break;
default:
JobFilterType = FilterType.NoFilter;
break;
}
if (_toFolders == null)
_toFolders = new List<string>();
_toFolders.Clear();
foreach (DataRow crw in rw.GetChildRows("Job_ToFolder"))
{
AddToFolder(crw["FolderPath"].ToString());
}
}
private static FileInfo[] GetFilesByRegEx(Regex rgx, string locPath)
{
DirectoryInfo d = new DirectoryInfo(locPath);
FileInfo[] fullFileList = d.GetFiles();
List<FileInfo> filteredList = new List<FileInfo>();
foreach (FileInfo fi in fullFileList)
{
if (rgx.IsMatch(fi.Name))
{
filteredList.Add(fi);
}
}
return filteredList.ToArray();
}
private static FileInfo[] GetFilesByFilter(string filter, string locPath)
{
DirectoryInfo d = new DirectoryInfo(locPath);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
private void CopyFiles(FileInfo[] files, string destPath)
{
foreach (FileInfo fi in files)
{
bool success = false;
int i = 0;
string copyToName = fi.Name;
string copyToExt = fi.Extension;
string copyToNameWithoutExt = Path.GetFileNameWithoutExtension(fi.FullName);
while (!success && i < 100)
{
i++;
try
{
if (File.Exists(Path.Combine(destPath, copyToName)))
throw new CopyFileExistsException();
File.Copy(fi.FullName, Path.Combine(destPath, copyToName));
success = true;
}
catch (CopyFileExistsException ex)
{
copyToName = String.Format("{0} ({1}){2}", copyToNameWithoutExt, i, copyToExt);
}
}
}
}
}
public class CopyFileExistsException : Exception
{
public string Message;
}
}
This code is also "screaming" to be broken down into smaller more specialized objects.
Your CopyJob object seems to be more of a manager of a list of jobs. I would maybe change the name of this to CopyJobManager or something. You could then have CopyJob be the base class for the different filter types. The common code, Execute() for example, would be defined in the base class, and the custom behavior, Filtering for example, would be handled in the derived classes. You would have a TextFilterCopyJob, a RegExFilterCopyJob, and a NoFilterCopyJob.
Where the Factory pattern could come into play is when you're building a list of CopyJobs. You could have a CopyJobFactory object that takes in a row from your dataset and returns the proper child version of CopyJob. CopyJobManager would then do its operations on a list of CopyJobs instead of a list of dataset rows.
Whenever I see Swithcs or bricks of Ifs, I jump to the conclusion that atleast a strategy pattern could be created.
a clean and easy way to set one up, is use a dictionary<>
in your case your going to want a key value based on the filterName your cases relate to, and the value will be a new object of the filters.
now you can merely give the string to the dictionarys TryGetValue method and have it retrieve the correct filter object for you, boom!
Now you can encapsulate the mapping of the filters <--> Strings, and keep the logic and use of the filters from having to see the logic of retrieving the correct object!
There's nothing wrong with using a switch statement like you have. It's not screaming for any design pattern other than that you can put it in a function so that you don't have the same switch twice.
The switch will be faster than using reflection, and the problem you're trying to solve doesn't really require the Factory pattern.
Here's some of what I did to implement a Factory pattern
First, I created an interface for the filter:
interface IFileFilter
{
string GetFilterName();
string GetFilterReadableName();
FileInfo[] GetFilteredFiles(string path, string filter);
}
then I created sub-filter classes for this interface:
class RegExFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "RegExFilter";
}
public string GetFilterReadableName()
{
return "RegEx Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fullFileList = d.GetFiles();
List<FileInfo> filteredList = new List<FileInfo>();
Regex rgx = new Regex(filter);
foreach (FileInfo fi in fullFileList)
{
if (rgx.IsMatch(fi.Name))
{
filteredList.Add(fi);
}
}
return filteredList.ToArray();
}
#endregion
}
class TextFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "TextFilter";
}
public string GetFilterReadableName()
{
return "Text Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
#endregion
}
class NoFileFilter : IFileFilter
{
#region IFileFilter Members
public string GetFilterName()
{
return "TextFilter";
}
public string GetFilterReadableName()
{
return "Text Filter";
}
public FileInfo[] GetFilteredFiles(string path, string filter)
{
DirectoryInfo d = new DirectoryInfo(path);
FileInfo[] fi = d.GetFiles(filter);
return fi;
}
#endregion
}
Then I created a Factory:
public static IFileFilter FileFilter(string filterName)
{
switch (filterName)
{
case "Text Filter":
return new TextFileFilter();
case "RegEx Filter":
return new RegExFileFilter();
default:
return new NoFileFilter();
}
}
I would suggest the following:
Refactor the switch statements (as #Jordan mentioned)
Add an extension method to convert the FilterType enum into an int and save that to the database rather than a string. E.g.
public static class FilterTypeExtensions
{
public static int AsNumeric(this FilterType filterType)
{
return (int)filterType;
}
}
As a minor point, the single line braces are horrible, either drop the braces or use proper spacing/indentation. :)

Categories

Resources