Any way to make this more generic? - c#

I have these two functions, used to search for a folder within a hierarchy:
public Folder<T> Find (string Path)
{
Folder<T> Result = null;
if (this.Path != Path &&
ChildrenDict != null)
{
foreach (KeyValuePair<long, Folder<T>> Child in ChildrenDict)
{
Result = Child.Value.Find (Path);
}
}
else
{
Result = this;
}
return Result;
}
public Folder<T> Find (long ID)
{
Folder<T> Result = null;
if (this.ID != ID &&
ChildrenDict != null)
{
foreach (KeyValuePair<long, Folder<T>> Child in ChildrenDict)
{
Result = Child.Value.Find (ID);
}
}
else
{
Result = this;
}
return Result;
}
As you can see, they are very similar to one another. How can I re-structure them so I don't have essentially the same code several times, one per each property I might want to use to find them?

Create a method with a condition parameter which does the logic:
protected Folder<T> Find(Func<Folder<T>, bool> condition) {
Folder<T> Result = null;
if(!condition(this) && ChildrenDict != null) {
foreach(var Child in ChildrenDict) {
Result = Child.Value.Find(condition);
}
} else {
Result = this;
}
return Result;
}
Rewrite your public Find methods as:
public Folder<T> Find(string path) {
return Find(f => f.Path == path);
}

Related

Cannot convert from 'void' to 'System.Collections.Generic.Dictionary<string, bool>'

I can't seem to add values into the dictionary. I am trying to extend the dictionary recursively but keep on getting the error/warning: "Cannot convert from 'void' to 'System.Collections.Generic.Dictionary<string, bool>'". I am a beginner so I am not sure how to resolve this error.
I am getting the error on the last line in the return statement specifically the model.Add(p,true) part.
namespace InferenceEngine
{
internal class TruthTable
{
TruthTable() { }
private List<string> ExtractSymbol(Sentence KB)
{
List<string> result = new List<string>();
if(KB.symbol != null)
{
result.Add(KB.symbol);
}
else
{
foreach(Sentence s in KB.child)
{
result.Concat(ExtractSymbol(s));
}
}
return result;
}
private bool PL_True(Sentence KB, Dictionary<string,bool> model)
{
if(KB.symbol != null)
{
return model[KB.symbol];
}
else if ( KB.connetives == "AND")
{
foreach (Sentence s in KB.child)
{
if(PL_True(s, model) == false)
{
return false;
}
return true;
}
}
else if (KB.connetives == "OR")
{
foreach (Sentence s in KB.child)
{
if (PL_True(s, model) == true)
{
return true;
}
return false;
}
}
else if (KB.connetives == "AND")
{
foreach (Sentence s in KB.child)
{
if (PL_True(s, model) == false)
{
return false;
}
return true;
}
}
else if (KB.connetives == "IF")
{
Sentence left = KB.child[0];
Sentence right = KB.child[KB.child.Count - 1];
if (PL_True(left,model) == true || PL_True(right,model) == false)
{
return false;
}
return true;
}
else if (KB.connetives == "IFF")
{
Sentence left = KB.child[0];
Sentence right = KB.child[KB.child.Count - 1];
if (PL_True(left, model) == true && PL_True(right, model) == false)
{
return false;
}
return true;
}
else if (KB.connetives == "NOT")
{
Sentence opposite = KB.child[0];
if (PL_True(opposite, model) == true)
{
return false;
}
return true;
}
return false;
}
public bool TT_Entails(Sentence KB, Sentence Alpha)
{
List<string> symbol1 = ExtractSymbol(KB);
List<string> symbol2 = ExtractSymbol(Alpha);
List<string> symbols = new List<string>();
symbols.Concat(symbol1);
symbols.Concat(symbol2);
Dictionary<string, bool> table = new();
return TT_Check_All(KB, Alpha, symbols, table );
}
private bool TT_Check_All(Sentence KB, Sentence Alpha, List<string> symbol, Dictionary<string, bool> model)
{
if(symbol.Count == 0)
{
if(PL_True(KB, model) == true)
{
return PL_True(Alpha, model);
}
return false;
}
string p = symbol[0];
symbol.RemoveAt(0);
List<string> rest = symbol;
return TT_Check_All(KB, Alpha, rest, model.Add(p,true)) && TT_Check_All(KB, Alpha, rest, model.Add(p, false));
}
}
}
The Add method on the dictionary returns void. So when you pass the result of model.Add(p, false) into TT_Check_All recursively, you are passing a void rather than the expected Dictionary<string, bool> type.
You can solve this issue by doing the Add before the recursive call and passing in model.

Recursive Search Binary Search Tree with one parameter

I am trying to search through a binary search tree using a recursive method in C#.
So far I am able to successfully execute this method using two parameters:
public bool Search(int value, Node start)
{
if(start == null) {
return false;
}
else if(value == start.value) {
return true;
}
else {
if(value < start.value) {
Search(value, start.LeftChild.value);
}
else {
Search(value, start.RightChild.value);
}
}
}
However I would like to see if there's a way to use only one parameter such as using the following method signature:
public bool Search(int value){}
I also have the following that I can use to access the tree:
public class BinarySearchTree
{
private Node<int> root;
public Node<int> Root { get => root; set => root = value; }
public BinarySearchTree()
{
this.root = null;
}
}
public bool Search(int value)
{
return SearchTree(value, root);
bool SearchTree(int value, Node<int> start)
{
if(start == null)
return false;
else if(value == start.Value)
return true;
else
{
if(value < start.Value)
return SearchTree(value, start.LeftChild);
else
return SearchTree(value, start.RightChild);
}
}
}
if there's a way to use only one parameter such as using the following method signature:
sure. make it a method in Node class.
public class Node
{
public Node LeftChild, RightChild;
public int value;
public bool Search(int value)
{
if (value == this.value)
{
return true;
}
else
{
if (value < this.value)
{
return this.LeftChild?.Search(value) ?? false;
}
else
{
return this.RightChild?.Search(value) ?? false;
}
}
}
}
then for tree call it as tree.Root.Search(0);

C# linked lists sort values and insert int in correct place

I am trying to create a linked list function which sorts the list into non-descending order (e.g. 1,2,6,9) and inserts the integer (5) into the correct place (e.g. 1,2,5,6,9).
So far I have created a temporary list to read from and a new list to write to. However, I haven't been able to successfully place the integer into the correct position.
Program console call code
LinkGen<int> link1 = new LinkGen<int>(5);
LinkListGen<int> testList = new LinkListGen<int>();
testList.AddItem(7);
testList.AddItem(6);
testList.AddItem(8);
testList.AddItem(9);
testList.AddItem(16);
testList.InsertInOrder(10);
LinkGen class
class LinkGen<T>
{
private T data;
private LinkGen<T> next;
public LinkGen(T item)
{
data = item;
next = null;
}
public LinkGen(T item, LinkGen<T> list)
{
data = item;
next = list;
}
public LinkGen<T> Next
{
set { this.next = value; }
get { return this.next; }
}
public T Data
{
set { this.data = value; }
get { return this.data; }
}
}
LinkListGen set up
class LinkListGen<T> where T:IComparable
{
private LinkGen<T> list;
public LinkListGen()
{
list = null;
}
AddItem, AppendItem and InsertInOrder Functions
public void AddItem(T item)
{
list = new LinkGen<T>(item, list);
}
public void AppendItem(T item)
{
LinkGen<T> temp = list;
if (temp == null)
list = new LinkGen<T>(item);
else
{
while (temp.Next != null)
{
temp = temp.Next;
}
temp.Next = new LinkGen<T>(item);
}
}
public void InsertInOrder(T item)
{
LinkGen<T> temp = list;
LinkListGen<T> newList = new LinkListGen<T>();
if (list == null)
AddItem(item);
else
{
while (list != null)
{
if (item.CompareTo(temp.Data) < 0)
{
newList.AppendItem(item);
}
else
{
newList.AppendItem(temp.Data);
temp = temp.Next;
}
}
//temp.Next = new LinkGen<T>(item);
}
}
(apologies about not originally giving enough code, if more is necessary please let me know)
After entering this while loop, when will list ever equal null again?
while (list != null)
{
if (item.CompareTo(temp.Data) < 0)
{
newList.AppendItem(item);
// and then...?
}
else
{
newList.AppendItem(temp.Data);
temp = temp.Next;
}
// never-ending loop
}
And then you do nothing with locally-scoped newList.
The idea is to find the node that your new node belongs after, then insert it there. The special case is when the new node goes at the head of the list, in which case you need to update your list head reference which you call list.
public void AppendItem(T item)
{
if (list == null)
list = new LinkGen<T>(item);
else {
LinkGen<T> temp = list;
while (temp.Next != null) {
temp = temp.Next;
}
temp.Next = new LinkGen<T>(item);
}
}
public void InsertInOrder(T item)
{
if (list == null || item.CompareTo(list.Data) < 0) {
list = new LinkGen<T>(item) { Next = list };
} else {
LinkGen<T> temp = list;
while (temp.Next != null && !(item.CompareTo(temp.Next.Data) < 0)) {
temp = temp.Next;
}
temp.Next = new LinkGen<T>(item) { Next = temp.Next };
}
}

EF ChangeTracker SoftDelete

I'm looking for a better way for implementing the following logic (HasAnyRelation and SetDeleteMarks) into ChangeTracker in order to avoid rewriting this logic for all my entities.
The problem is that once we call Remove() it will drop all relations with child/parent entities and I can't check the relations into ChangeTracker anymore.
In this post I got a suggestion to implement a copy of my previous entity to keep my collections intact after Remove(). However it works, I also would have to implement the logic many times.
Does anybody would have any other approach to achieve it?
Regards
CONTROLLER DELETE ACTION
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Delete(Sector sector)
{
if (ModelState.IsValid)
{
var currentEntity = db.Sector.Find(sector.SectorId);
var hasAnyRelation = EntityHelper.HasAnyRelation(currentEntity);
if (hasAnyRelation)
{
currentEntity = (Sector)EntityHelper.SetDeleteMarks(currentEntity);
db.Sector.Attach(currentEntity);
db.Entry(currentEntity).State = EntityState.Modified;
}
else
{
db.Sector.Attach(currentEntity);
db.Sector.Remove(currentEntity);
}
db.SaveChanges();
}
}
ENTITY HELPER
public static class EntityHelper
{
public static object SetDeleteMarks(object entityObj)
{
var deletedProperty = entityObj.GetType().GetProperties().Where(p => p.Name == "Deleted").FirstOrDefault();
var nameProperties = entityObj.GetType().GetProperties().Where(p => p.Name.Contains("Name"));
if (deletedProperty != null)
{
deletedProperty.SetValue(entityObj, true);
foreach (var nameProperty in nameProperties)
{
var deletedMark = "(*)";
var currentValue = nameProperty.GetValue(entityObj).ToStringNullSafe();
if (!currentValue.Contains(deletedMark) && !String.IsNullOrEmpty(currentValue))
{
nameProperty.SetValue(entityObj, String.Format("{0} {1}", currentValue, deletedMark).Trim());
}
}
}
return entityObj;
}
public static bool HasAnyRelation(object entityObj)
{
var collectionProps = GetManyRelatedEntityNavigatorProperties(entityObj);
foreach (var item in collectionProps)
{
var collectionValue = GetEntityFieldValue(entityObj, item.Name);
if (collectionValue != null && collectionValue is IEnumerable)
{
var col = collectionValue as IEnumerable;
if (col.GetEnumerator().MoveNext())
{
return true;
}
}
}
return false;
}
private static object GetEntityFieldValue(this object entityObj, string propertyName)
{
var pro = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).First(x => x.Name == propertyName);
return pro.GetValue(entityObj, null);
}
private static IEnumerable<PropertyInfo> GetManyRelatedEntityNavigatorProperties(object entityObj)
{
var props = entityObj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(x => x.CanWrite && x.GetGetMethod().IsVirtual && x.PropertyType.IsGenericType == true);
return props;
}
}

Get Full Class Property "Tree" Name as String

What I am trying to do is probably a little strange.
But I am trying to (this is the best I can explain it) use reflection to get a full class property tree name as a string.
Successful example so far:
By using expressions I am able to convert:
() => Model.Cargo.Id
into the string:
"Model.Cargo.Id"
My problem now is when I am using an array in the mix, I do not get the array name. All I get is the last properties name.
Unsuccessful example:
Model.CargoTasks[j].IsSet
Only returns me the string:
"IsSet"
Ideally I want the following string result:
"Model.CargoTasks[0].IsSet"
I am probably asking a little much to get the index included in the result, but it would be fantasic if this were possible.
The code I am using to process these examples is as follows:
public static string ToMemberAccess<TResult>(this Expression<Func<TResult>> expression)
{
// Get the body of the expression
Expression body = expression.Body;
if (body.NodeType != ExpressionType.MemberAccess && body.NodeType != ExpressionType.Convert)
{
throw new ArgumentException("Property expression must be of the form '() => SomeProperty'", "expression");
}
var memberExpression = expression.Body as MemberExpression ?? ((UnaryExpression)expression.Body).Operand as MemberExpression;
var stuff = GetMemberNames(memberExpression);
stuff.Reverse();
return string.Join(".", stuff);
}
static List<string> GetMemberNames(MemberExpression expression, List<string> actual = null)
{
if (actual == null) actual = new List<string>();
var member = expression.Member;
var subExp = expression.Expression as MemberExpression;
actual.Add(member.Name);
if(subExp != null) actual = GetMemberNames(subExp, actual);
return actual;
}
Thanks in advance! Any help will be greatly appreciated!
To get the value in the indexer, you must compile and execute the expression - which is prohibitively expensive, but it can be done using a modified version of ExpressionStringBuilder. Note that I've added a parameter, compileConstants. When it's set to false, the output will be something like Model.CargoTasks[_.j].IsSet.
Note that this sample visitor is incomplete (i.e. it doesn't support all kinds of expressions). You can complement it using the code in GitHub.
public static string ToMemberAccess<TResult>(Expression<Func<TResult>> expression, bool compileConstants = false)
{
var builder = new ExpressionStringBuilder(compileConstants);
builder.Visit(expression);
return builder.ToString();
}
internal class ExpressionStringBuilder : ExpressionVisitor
{
private readonly bool _compileConstants;
private readonly StringBuilder _out;
public ExpressionStringBuilder(bool compileConstants)
{
_compileConstants = compileConstants;
_out = new StringBuilder();
}
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value != null)
{
string text = node.Value.ToString();
if (node.Value is string)
{
Out("\"");
Out(text);
Out("\"");
}
else if (text == node.Value.GetType().ToString())
{
Out('_');
}
else
{
Out(text);
}
}
else
{
Out("null");
}
return node;
}
protected override Expression VisitMethodCall(MethodCallExpression node)
{
int num = 0;
Expression expression = node.Object;
if (Attribute.GetCustomAttribute(node.Method, typeof(ExtensionAttribute)) != null)
{
num = 1;
expression = node.Arguments[0];
}
var name = node.Method.Name;
var isIndexer = name == "get_Item";
if (expression != null)
{
Visit(expression);
if (!isIndexer)
{
Out('.');
}
}
if (isIndexer)
Out('[');
else
{
Out(name);
Out('(');
}
int i = num;
int count = node.Arguments.Count;
while (i < count)
{
if (i > num)
{
Out(", ");
}
VisitArgument(node.Arguments[i]);
i++;
}
Out(isIndexer ? ']' : ')');
return node;
}
protected override Expression VisitIndex(IndexExpression node)
{
if (node.Object != null)
{
Visit(node.Object);
}
else
{
Out(node.Indexer.DeclaringType.Name);
}
if (node.Indexer != null)
{
Out(".");
Out(node.Indexer.Name);
}
Out('[');
for (var index = 0; index < node.Arguments.Count; index++)
{
if (index > 0)
{
Out(", ");
}
var expression = node.Arguments[index];
VisitArgument(expression);
}
Out(']');
return node;
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
Visit(node.Body);
return node;
}
protected override Expression VisitMember(MemberExpression node)
{
OutMember(node.Expression, node.Member);
return node;
}
public override string ToString()
{
return _out.ToString();
}
private void VisitArgument(Expression expression)
{
if (_compileConstants)
{
// TODO: possibly check the expression is not dependent on parameters
var value = Expression.Lambda(expression).Compile().DynamicInvoke();
Out(value + string.Empty);
}
else
{
VisitArgument(expression);
}
}
private void OutMember(Expression instance, MemberInfo member)
{
if (instance != null)
{
Visit(instance);
if (_out.Length > 0)
Out('.');
Out(member.Name);
return;
}
Out(member.DeclaringType.Name + "." + member.Name);
}
private void Out(char c)
{
_out.Append(c);
}
private void Out(string s)
{
_out.Append(s);
}
}

Categories

Resources