Get all folders from Composite - c#

I'm creating a tree structure of a given folder (only folders no files)
also i return the security permission of each folder and add it to a list
Now how can i Loop through this composite and get all items and sub items
public abstract class FolderComponent:IEnumerable
{
public string FullName { get; set; }
public string Name { get; set; }
public List<string[]> Rules { get; set; }
public abstract void AddFolder(FolderComponent folderComponent);
public abstract IEnumerator GetEnumerator();
public abstract void AssignRules();
}
public class Folder : FolderComponent
{
public IList<FolderComponent> FolderComponents { get; set; }
public Folder(string path)
{
FullName = path;
FolderComponents = new List<FolderComponent>();
Rules = new List<string[]>();
}
public override void AddFolder(FolderComponent folderComponent)
{
FolderComponents.Add(folderComponent);
}
public override IEnumerator GetEnumerator()
{
return FolderComponents.GetEnumerator();
}
public override void AssignRules()
{
// some code
string[] rules = new string[]{"Read","Write","Execute"};
Rules.Add(rules);
}
}
public class Program
{
private static FolderComponent GetFolders(string path)
{
FolderComponent folder = new Folder(path);
folder.AssignRules();
foreach (var directory in Directory.GetDirectories(path))
{
folder.AddFolder(GetFolders(directory));
}
return folder;
}
public static void Main()
{
FolderComponent folder = GetFolders(#"C\:Test");
// How can i loop though all folder structure inside folder?
}
}

If you want to do something like this with your Folder class:
FolderComponent folders = GetFolders(#"C\:Test");
foreach (var folder in folders) { Console.WriteLine(folder.FullName); }
and get the full directory tree printed, then the GetEnumerator method needs to have logic to traverse the tree. For example
public override IEnumerator<FolderComponent> GetEnumerator()
{
// Return the current element
yield return this;
// Work through the collection of components in this folder ...
foreach (var component in FolderComponents)
{
// ... and traverse all the subfolders in each component.
// Note that this recursively calls this GetEnumerator
// method on the subfolders to work down the tree.
foreach (var subfolder in component)
{
yield return subfolder;
}
}
}

I added a method to your FolderComponent class and implement that
see if that can do the thing:
public abstract class FolderComponent : IEnumerable
{
public string FullName { get; set; }
public string Name { get; set; }
public List<string[]> Rules { get; set; }
public abstract void AddFolder(FolderComponent folderComponent);
public abstract IEnumerator GetEnumerator();
public abstract void AssignRules();
public abstract List<FolderComponent> GetAllItems();
}
public class Folder : FolderComponent
{
public IList<FolderComponent> FolderComponents { get; set; }
public Folder(string path)
{
FullName = path;
FolderComponents = new List<FolderComponent>();
Rules = new List<string[]>();
}
public override void AddFolder(FolderComponent folderComponent)
{
FolderComponents.Add(folderComponent);
}
public override IEnumerator GetEnumerator()
{
return FolderComponents.GetEnumerator();
}
public override void AssignRules()
{
// some code
string[] rules = new string[] { "Read", "Write", "Execute" };
Rules.Add(rules);
}
public override List<FolderComponent> GetAllItems()
{
var resultItems = new List<FolderComponent> {this};
foreach (var folderComponent in FolderComponents)
{
resultItems.AddRange(folderComponent.GetAllItems());
}
return resultItems;
}
}
public class Program
{
private static FolderComponent GetFolders(string path)
{
FolderComponent folder = new Folder(path);
folder.AssignRules();
foreach (var directory in Directory.GetDirectories(path))
{
folder.AddFolder(GetFolders(directory));
}
return folder;
}
public static void Main()
{
FolderComponent rootfolder = GetFolders(#"D:\4Share");
var allItems = rootfolder.GetAllItems();
foreach (var folderComponent in allItems)
{
Console.WriteLine(folderComponent.FullName);
}
Console.ReadLine();
}

you should add a list of folder type (children).
FolderComponent Parent;
List<FolderComponent> children;
And add a child when u find a folder inside specific folder. You can add parent for backward processing as well.
var directoryInfo = new DirectoryInfo(folderPath);
foreach (var directory in directoryInfo)
{
FolderComponent newSubFolder = new FolderComponent();
newSubFolder.Parent = this;
// get whatever you want like name, permissions etc.
children.Add(newSubFolder);
}
You need something like this in your code (depends on implementation)
PrintFolders()
{
foreach(var child in children)
child.PrintFolders();
Console.WriteLine(FolderName);
}

Related

Best way to show all subfolders and its files in uwp

I have stored all subfolder names and it's corresponding file names(from local folder) in a class. Now I want to display it in a good way. And also need to access that files when user selects it. What is the best way to achieve it?
public class SubFolders
{
public string ItemName { get; set; }
public ObservableCollection<SubFolderFiles> SubItemsList { get; set; }
}
public class SubFolderFiles
{
public string SubItemName { get; set; }
}
Best way to show all subfolders and its files in uwp.
For this requirement, you need to create a relatively complete model like the following Illustration.
The above is recursive model, and I have make a class to match it.
public class Folder
{
public string FolderName { get; set; }
private ObservableCollection<File> _subFiles;
public ObservableCollection<File> SubFiles
{
get { return _subFiles ?? (_subFiles = new ObservableCollection<File>()); }
set
{
_subFiles = value;
}
}
private ObservableCollection<Folder> _subFolder;
public ObservableCollection<Folder> SubFolders
{
get { return _subFolder ?? (_subFolder = new ObservableCollection<Folder>()); }
set
{
_subFolder = value;
}
}
public Folder()
{
}
}
public class File
{
public string FileName { get; set; }
}
As you know, if you want to display the folders and files where in one folder on the ListView, you need to converter them into abstract listview items.
public class Item
{
public string ItemName { get; set; }
public ItemType IType { get; set; }
}
public enum ItemType
{
File,
Folder
}
Usage
FolderService.cs
public class FolderService
{
// private Folder FolderModel;
public async static Task<Folder> GetFolderInfoAsync(StorageFolder SelectFolder)
{
var FolderModel = new Folder();
FolderModel.FolderName = SelectFolder.Name;
IReadOnlyList<StorageFile> fileList = await SelectFolder?.GetFilesAsync();
foreach (StorageFile file in fileList)
{
var subFile = new File();
subFile.FileName = file.Name;
FolderModel.SubFiles.Add(subFile);
}
IReadOnlyList<StorageFolder> folderList = await SelectFolder?.GetFoldersAsync();
foreach (StorageFolder folder in folderList)
{
var subFolder = new Folder();
subFolder.FolderName = folder.Name;
FolderModel.SubFolders.Add(subFolder);
}
return FolderModel;
}
public async static Task<ObservableCollection<Item>>GetItems(StorageFolder SelectFolder)
{
var Model = await GetFolderInfoAsync(SelectFolder);
var Items = new ObservableCollection<Item>();
foreach (var file in Model.SubFiles)
{
var item = new Item
{
ItemName = file.FileName,
IType = ItemType.File
};
Items.Add(item);
}
foreach (var folder in Model.SubFolders)
{
var item = new Item
{
ItemName = folder.FolderName,
IType = ItemType.Folder
};
Items.Add(item);
}
return Items;
}
}
ManPageViewModel.cs
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
}
public Command PickCommand => new Command(() => this.BtnClick());
private async void BtnClick()
{
StorageFolder Selectfolder = ApplicationData.Current.LocalFolder;
this.Items = await FolderService.GetItems(Selectfolder);
}
private ObservableCollection<Item> _items;
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged([CallerMemberName] string PropertyName = null)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(PropertyName));
}
public ObservableCollection<Item> Items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged();
}
}
}

Fluent Builder pattern which returns root type

I want to create builder for my purpose, with such call chain:
User user = new CommonBuilder(new UserNode()).Root //generic parameter, currently is User
.Group.Group.Folder.Build();
Here is the code, which I use:
public abstract class AbstractNode
{
public Guid Id { get; } = Guid.NewGuid();
}
public abstract class AbstractNode<T> where T : AbstractNode<T>
{
}
public class CommonBuilder<T> where T : AbstractNode<T>
{
public T Root { get; private set; }
public CommonBuilder(T root)
{
Root = root;
}
}
public class UserNode : AbstractNode<UserNode>
{
private GroupNode _group;
public GroupNode Group
{
get
{
if (_group is null)
{
_group = new GroupNode();
}
return _group;
}
}
}
public class GroupNode : AbstractNode<GroupNode>
{
private GroupNode _group;
public GroupNode Group
{
get
{
if (_group is null)
{
_group = new GroupNode();
}
return _group;
}
}
private FolderNode _folder;
public FolderNode Folder
{
get
{
if (_folder is null)
{
_folder = new FolderNode();
}
return _folder;
}
}
}
public class FolderNode : AbstractNode<FolderNode>
{
}
The problem is in the Build() method, which need to return Root from CommonBuilder, not the File.
Where must I place Build() method, which must be always called at the end of a chain, which returns Root of a builder?
In case when it's required to make a chain the same object should be returned, even as another interface check first and second examples of implementation Builder with Fluent intefaces
I've tried to implement your case to fit the role, check if it will fits your requirements:
public interface IGroup<T>
{
IGroup<T> Group { get; }
IFolder<T> Folder { get; }
}
public interface IFolder<T>
{
T Build();
}
Builder implements all required interfaces. And returns itself in each call. In general you can put Build method in the builder itself and call it separately after the end of chain execution.
public class CommonBuilder<T> : IGroup<T>, IFolder<T> where T: INode, new()
{
private T _root = new T();
public T Build()
{
return _root;
}
public IGroup<T> Group
{
get
{
_root.MoveToGroup();
return this;
}
}
public IFolder<T> Folder
{
get
{
_root.MoveToFolder();
return this;
}
}
}
Because of generics it's required to set some limitations on generic parameter which is done with INode interface
public interface INode
{
void MoveToGroup();
void MoveToFolder();
}
Testing user object
public class User : INode
{
public StringBuilder Path { get; } = new StringBuilder();
public void MoveToFolder()
{
Path.AppendLine("Folder");
}
public void MoveToGroup()
{
Path.AppendLine("Group");
}
public override string ToString()
{
return Path.ToString();
}
}
And the call will looks like
var user = new CommonBuilder<User>().Group.Group.Folder.Build();
EDIT
Maybe as a the first stage it makes sence to get rid of Fluent interfaces and implement logic using just a Builder:
public class FolderNode : INode<Folder>
{
private readonly Folder _folder = new Folder();
public Folder Build()
{
return _folder;
}
public void AppendGroup()
{
_folder.Path.AppendLine("Folder Group");
}
public void AppendFolder()
{
_folder.Path.AppendLine("Folder Folder");
}
}
public class UserNode : INode<User>
{
private readonly User _user = new User();
public User Build()
{
return _user;
}
public void AppendGroup()
{
_user.Path.AppendLine("Group");
}
public void AppendFolder()
{
_user.Path.AppendLine("Folder");
}
}
public class CommonBuilder<T, TNode> where TNode : INode<T>
{
private readonly TNode _root;
public CommonBuilder(TNode root)
{
_root = root;
}
public T Build()
{
return _root.Build();
}
public CommonBuilder<T, TNode> Group {
get
{
_root.AppendGroup();
return this;
}
}
public CommonBuilder<T, TNode> Folder {
get
{
_root.AppendFolder();
return this;
}
}
}
public interface INode<out T>
{
T Build();
void AppendGroup();
void AppendFolder();
}
public class Folder
{
public StringBuilder Path { get; } = new StringBuilder();
public override string ToString()
{
return Path.ToString();
}
}
public class User
{
public StringBuilder Path { get; } = new StringBuilder();
public override string ToString()
{
return Path.ToString();
}
}
Usage:
var user = new CommonBuilder<User, UserNode>(new UserNode()).Group.Group.Folder.Build();
var folder = new CommonBuilder<Folder, FolderNode>(new FolderNode()).Group.Folder.Group.Folder.Build();

Implementing IEnumerable for Leaf Nodes of Composite Pattern

I've implemented the composite pattern as follows
public interface IComponent
{
string Name { get; }
}
public interface IComposite : IComponent
{
void AddRange(IEnumerable<IComponent> components);
}
public interface ILeaf : IComponent
{
string Content { get; }
string Parent { get; }
}
public class Composite : IComposite
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
}
public class Leaf : ILeaf
{
public string Name { get; }
public string Content { get; }
public string Parent { get; }
public Leaf(string name, string content, string parent)
{
Name = name;
Content = content;
Parent = parent;
}
}
I've populated the composite from an xml file as follows
var collection = XElement.Load(#"C:\somexml.xml");
var composite = CreateComposite(collection);
where
public IComponent CreateComposite(XElement element)
{
if (!element.HasElements)
return new Leaf(element.Name.LocalName, element.Value, element.Parent.Name.LocalName);
var composite = new Composite(element.Name.LocalName);
composite.AddRange(element.Elements().Select(CreateComposite));
return composite;
}
This populates my composite as expected - great! However, I'd now like my composite to return an iterator via the implementation of IEnumerable. So I tried this
public class Composite : IComposite, IEnumerable<IComponent>
{
// return an iterator?
private readonly List<IComponent> _children = new List<IComponent>();
public Composite(string name)
{
Name = name;
}
public string Name { get; }
public void AddRange(IEnumerable<IComponent> components)
{
_children.AddRange(components);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
}
}
}
But this only iterates through the top level of components, i.e., any components nested within _children are not returned. How do I update this to recursively iterate through all components?
You can iterate recursively like this (it will do iteration in depth-first manner):
public interface IComposite : IComponent, IEnumerable<IComponent>
{
void AddRange(IEnumerable<IComponent> components);
}
public IEnumerator<IComponent> GetEnumerator()
{
foreach (var child in _children)
{
yield return child;
var composite = child as IComposite;
if (composite != null) {
foreach (var sub in composite) {
yield return sub;
}
}
}
}
If you want to avoid the cast to IComposite - you need to redesign your interfaces and make your Composite to hold a list of another IComposites instead of components. Then ILeft will also become IComposite with dummy implementation.
You could implement the traversal recursively using Linq as follows.
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.Concat(_children.SelectMany(iChild => iChild.GetSuccessors());
}
If depht-first traversal is desired, you can use the following implementation.
public IEnumerable<IComponent> GetSuccessors()
{
return _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
}
Or, if you need it using your initial syntax, you could use the following.
public IEnumerator<IComponent> GetEnumerator()
{
var Successors
= _children
.SelectMany(iChild => new IComponent[]{iChild}.Concat(iChild.GetSuccessors()));
foreach (var iSuccessor in Successors)
{
yield return iSuccessor;
}
}

Get All Directories of a Folder Path Recursively into my Poco

I wrote a poco like this :
public class MyDirectory
{
public string Path { get; set; }
public List<MyDirectory> MyDirectories { get; set; }
}
then I wrote 2 methods like this
private static List<MyDirectory> lst = new List<MyDirectory>();
private static void DirSearch(string dir)
{
var dirs = Directory.GetDirectories(dir);
foreach (string d in dirs)
{
var ddd = new MyDirectory();
ddd.Path = d;
ddd.MyDirectories = GetList(Directory.GetDirectories(d));
lst.Add(ddd);
DirSearch(d);
}
}
private static List<MyDirectory> GetList(string[] list)
{
var lst = new List<MyDirectory>();
foreach (var l in list)
{
lst.Add(new MyDirectory() { Path = l });
}
return lst;
}
but I does not work Can anybody change it to working method ?
I dont know How fill my Poco correctly. I need recursively method.
If you want to recursively load directories then you don't GetList method. The method DirSearch is sufficient but need some refactoring like below:
private static List<MyDirectory> DirSearch(string directory)
{
var directories = new List<MyDirectory>();
foreach (var l in Directory.EnumerateDirectories(directory))
{
directories.Add(new MyDirectory
{
Path = l,
MyDirectories = DirSearch(l)
});
}
return directories;
}
Notice in the snippet I'm using Directory.EnumerateDirectories instead of Directory.GetDirectories. I do this because the latter isn't performant.
To call this method just do this:
lst = DirSearch(pathToYourDirectory);
You can make it better by using IEnumerable instead of List as type of MyDirectories property.
Your code will finally look like this :
public class MyDirectory
{
public string Path { get; set; }
public IEnumerable<MyDirectory> MyDirectories { get; set; }
}
private static IEnumerable<MyDirectory> DirSearch(string directory)
{
return Directory.EnumerateDirectories(directory).Select(l => new MyDirectory
{
Path = l,
MyDirectories = DirSearch(l)
});
}
Indeed your static property lst need to be of type IEnumerable<MyDirectory> also.
By doing those changes you will be able to start using each instance of MyDirectory instead of waiting all subdirectories to be returned when using List.
Instead of do recursive, you can use this code
Directory.GetDirectories(path, "*", SearchOption.AllDirectories)
Create cunstructor for your POCO.
public class MyDirectory
{
public MyDirectory()
{
MyDirectories = new List<MyDirectory>();
}
public string Path { get; set; }
public List<MyDirectory> MyDirectories { get; set; }
}
Recursive Method:
private MyDirectory FindRecursiveDirectories(string dir)
{
var rootDirectory = new MyDirectory();
rootDirectory.Path = dir;
foreach (var subDirectory in Directory.EnumerateDirectories(dir))
{
var myDir = FindRecursiveDirectories(subDirectory);
rootDirectory.MyDirectories.Add(myDir);
}
return rootDirectory;
}
Finally call FindRecursiveDirectories Method.
var result = FindRecursiveDirectories(yourDirectory);

C# composite pattern : Program.IAsset is not enumerable

Hi I am trying to create a directory structure using composite pattern. I have an interface IAsset which is implemented by the file and folder class. So both are an Asset. Now I want to loop through all the files in all the folders but I am getting the error message:
Program.IAsset is not enumerable
This error message is in the inner foreach loop of getassetSize() method.
public class Program
{
public interface IAsset
{
double GetAssetSize();
void AddAsset(IAsset a);
}
public class File : IAsset
{
public double Size { get; set; }
public double GetAssetSize()
{
return Size;
}
public void AddAsset(IAsset a)
{
Console.WriteLine("No asset can be added to a file");
}
}
public class Folder : IAsset
{
public double Size { get { return _size; } set { _size = value; } }
private double _size = 0;
public List<IAsset> list = new List<IAsset>();
public double GetAssetSize()
{
foreach (var asset in list)
{
foreach (var x in asset)
{
// _size = x.GetAssetSize();
}
}
return _size;
}
public void AddAsset(IAsset a)
{
list.Add(a);
}
}
To fit into the composite pattern IAsset would need to inherit IEnumerable<IAsset> or provide a member which implements it. For example:
public interface IAsset : IEnumerable<IAsset>
{
double GetAssetSize();
void AddAsset(IAsset a);
}
public class File : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
return new IAsset[0].GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
public class Folder : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
return this.list.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
}
Or this:
public interface IAsset
{
double GetAssetSize();
void AddAsset(IAsset a);
IEnumerable<IAsset> Assets { get; }
}
public class File : IAsset
{
...
public IEnumerator<IAsset> Assets
{
get { return new IAsset[0]; }
}
}
public class Folder : IAsset
{
...
public IEnumerator<IAsset> GetEnumerator()
{
get { return this.list; }
}
}
Assuming that you want to sum the size of the files in the directory, you have one too many loops going. This would do it...
public double GetAssetSize()
{
foreach (var asset in list)
{
_size += x.GetAssetSize();
}
return _size;
}

Categories

Resources