I have the following codes and I would like to write it in a way that I have minimum duplication of codes.
if (Categories != null)
{
bool flag=false;
foreach (dynamic usableCat in Category.LoadForProject(project.ID))
{
foreach (dynamic catRow in Categories)
{
if (usableCat.ID == catRow.ID)
flag = true;
}
if (!flag)
{
int id = usableCat.ID;
Category resolution = Category.Load(id);
resolution.Delete(Services.UserServices.User);
}
}
}
if (Priorities != null)
{
bool flag = false;
foreach (dynamic usableCat in Priority.LoadForProject(project.ID))
{
foreach (dynamic catRow in Priorities)
{
if (usableCat.ID == catRow.ID)
flag = true;
}
if (!flag)
{
int id = usableCat.ID;
Priority resolution = Priority.Load(id);
resolution.Delete(Services.UserServices.User);
}
}
}
Please note that Category and priority do not have a common base type or interface that includes ID.
void DeleteUsable<Ttype>(IEnumerable<Ttype> usables, IEnumerable<Ttype> collection, Func<int, Ttype> load)
{
bool flag = false;
foreach (dynamic usableCat in usables)
{
foreach (dynamic catRow in collection)
{
if (usableCat.ID == catRow.ID)
flag = true;
}
if (!flag)
{
int id = usableCat.ID;
Ttype resolution = load(id);
resolution.Delete(Services.UserServices.User);
}
}
}
Edit:
call it:
if (Categories != null)
DeleteUsable(Category.LoadForProject(project.ID), Categories, Categoriy.Load);
if (Priorities != null)
DeleteUsables(Priority.LoadForProject(project.ID), Priorities, Priority.Load);
Let me suggest an alternative approach: Instead of factoring out the flag thing, use LINQ to remove the need for the flag loop:
if (Categories != null)
{
foreach (var usableCat in Category.LoadForProject(project.ID))
{
if (!Categories.Any(row => usableCat.ID == row.ID))
Category.Load(usableCat.ID).Delete(Services.UserServices.User);
}
}
if (Priorities != null)
{
foreach (var usablePri in Priority.LoadForProject(project.ID))
{
if (!Priorities.Any(row => usablePri.ID == row.ID))
Priority.Load(usablePri.ID).Delete(Services.UserServices.User);
}
}
I'd recommend a method like this (since you have access to dynamic types):
void DeleteUsables(dynamic usablesResource, dynamic usablesCatalog)
{
bool flag = false;
foreach (dynamic usableCat in usablesCatalog.LoadForProject(project.ID))
{
foreach (dynamic catRow in usablesResource)
{
if (usableCat.ID == catRow.ID)
flag = true;
}
if (!flag)
{
int id = usableCat.ID;
dynamic resolution = usablesCatalog.Load(id);
resolution.Delete(Services.UserServices.User);
}
}
}
which you would then call like this:
if (Categories != null)
{
DeleteUsables(Categories, Category)
}
if (Priorities != null)
{
DeleteUsables(Priorities, Priority)
}
Related
I'm trying to validate an entity coming from an External context has not changed.
public class Employee
{
public int Id { get; set; }
public string Name { get; set; }
}
I have a method which takes in an entity which has not been loaded from the context.
public bool Validate(Employee employee)
{
using (var context = new Context())
{
return context.Entry(employee).State == EntityState.Modified;
}
}
I would like to attach and verify that the attached entity is not modified from whats in the database.
I would prefer not to manually have to iterate of the properties. Is there a way to hack around this?
No need to attach the external entity. You can use the external entity to set values of the database entity and then check the state of the latter:
public bool Validate(Employee externalEmployee)
{
using var context = new Context(); // C# 8.0
var dbEntity = context.Where(x => x.Id == externalEmployee.Id).SingleOrDefault();
if (dbEntity != null)
{
context.Entry(dbEntity).CurrentValues.SetValues(externalEmployee);
return context.Entry(dbEntity).State == EntityState.Modified;
}
return false; // Or true, depending on your semantics.
}
You can try:
public static List<string> GetChanges<T>(this T obj, T dbObj)
{
List<string> result = new List<string>();
var type = typeof(T);
foreach (var prop in type.GetProperties())
{
var newValue = prop.GetValue(obj, null);
var dbValue = prop.GetValue(dbObj, null);
if(newValue == null && dbValue != null)
{
result.Add(prop.Name);
continue;
}
if (newValue != null && dbValue == null)
{
result.Add(prop.Name);
continue;
}
if (newValue == null && dbValue == null)
continue;
if (!newValue.ToString().Equals(dbValue.ToString()))
result.Add(prop.Name);
}
return result;
}
if resultList.Count > 0, your object has changes.
In your Validate Method:
public bool Validate(Employee employee)
{
using (var context = new Context())
{
Employee dbEmployee = context.Employee.Find(employee.Id);
if(employee.GetChanges(dbEmployee).Count > 0)
return true;
return false;
}
}
It's a god workaround =D
Works for me!
if (!string.IsNullOrEmpty(View.Panel1.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN1 = View.Panel1;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN2 = View.Panel2;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel3.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN3 = View.Panel3;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel4.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN4 = View.Panel4;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
if (!string.IsNullOrEmpty(View.Panel5.ToString()))
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.PAN5 = View.Panel5;
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
.....
.....
I have a foreach loop like above and i'm repeating the same code inorder to pass each panel value.
I'm trying to reduce the repeated code like below( but not sure it is correct way )
if (!string.IsNullOrEmpty(View.Panel1.ToString()))
{
setpanelinfo(View.Panel1.ToString(),PAN1)
}
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
{
setpanelinfo(View.Panel2.ToString(),PAN2)
}
....
....
....
public void setpanelinfo(string strpanelvalue, string PAN)
{
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.+ "PAN1" = strpanelvalue; // ERROR
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
Is there a better way to write this above foreach logic with minimal code?
One approach to simplifying this is to use an Action callback for each specific case:
void HandlePanel(string panel, Action<OtherFeatures> action)
{
if (!string.IsNullOrEmpty(panel))
{
foreach (var of in FeaturesInfo)
{
if (of != null)
{
action(of);
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
}
}
...
HandlePanel(View.Panel1.ToString(), of => of.PAN1 = View.Panel1);
HandlePanel(View.Panel2.ToString(), of => of.PAN2 = View.Panel2);
HandlePanel(View.Panel3.ToString(), of => of.PAN3 = View.Panel3);
HandlePanel(View.Panel4.ToString(), of => of.PAN4 = View.Panel4);
....
Use the Controls collection of the form object:
(typecast)Controls(of+"PAN1").SomeProperty = some value;
I just think foreach-ing the collection three times is a little wasteful. Maybe something like this might be a little more performant
foreach (var of in FeaturesInfo)
{
if (of != null)
{
TestAndSet(View.Panel1.ToString(), text => of.PAN1 = text);
TestAndSet(View.Panel2.ToString(), text => of.PAN2 = text);
TestAndSet(View.Panel3.ToString(), text => of.PAN3 = text);
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
break;
}
}
....
private void TestAndSet(String panel, Action<string> setAction)
{
if (!string.IsNullOrEmpty(panel))
{
setAction(panel);
}
}
In your case, you can do only one foreach and move the test inside of the loop.
foreach (OtherFeatures of in FeaturesInfo)
{
if (of != null)
{
of.NumOtherFeatures = null;
of.OtherFeaturesDesc = null;
if (!string.IsNullOrEmpty(View.Panel1.ToString()))
of.PAN1 = View.Panel1;
if (!string.IsNullOrEmpty(View.Panel2.ToString()))
of.PAN2 = View.Panel2;
if (!string.IsNullOrEmpty(View.Panel3.ToString()))
of.PAN3 = View.Panel3;
if (!string.IsNullOrEmpty(View.Panel4.ToString()))
of.PAN4 = View.Panel4;
if (!string.IsNullOrEmpty(View.Panel5.ToString()))
of.PAN5 = View.Panel5;
break;
}
}
I have a base class called Part and derived classes like Wire or Connector and many more that inherit from Part.
Now I want to implement a search function that searches all Properties of the derived classes for a string.
If necessary that string should be tried to be converted to the type of the Property. The Properties can also be Lists and should be searched on the first level.
class Part
{
public int Id { get; set; }
public string Name { get; set; }
}
class Wire : Part
{
public NumberWithUnit Diameter { get; set; }
public Weight Weight { get; set; }
}
class Connector : Part
{
public List<Part> ConnectedParts { get; set; }
}
I know how to generally search through the Properties of base types with Reflection like this
private bool SearchProperties<T>(T part, string searchString) where T : Part
{
var props = typeof(T).GetProperties();
foreach (var prop in props)
{
var value = prop.GetValue(part);
if (value is string)
{
if (string.Equals(value, searchString))
return true;
}
else if (value is int)
{
int v;
if (int.TryParse(searchString, out v))
{
if(v == (int) value)
return true;
}
}
}
return false;
}
But that would be a long list of types and I have Properties of Type Weight for instance and many more. Is there some kind of general way to search without casting all types?
Consider going the opposite direction with your conversion. Rather than converting your search string into each possible value, just convert the value into a string:
private bool SearchProperties<T>(T part, string searchString) where T : Part
{
var props = typeof(T).GetProperties();
foreach (var prop in props)
{
var value = prop.GetValue(part);
if (value is IEnumerable)
{
// special handling for collections
}
else if(value != null)
{
string valueString = value.ToString();
if (string.Equals(valueString, searchString))
return true;
}
}
return false;
}
Besides working pretty well for most built-in types, the only thing you have to do to get it to work for Weight, etc. is make sure they implement ToString().
Another solution would be to use TypeDescriptor:
private bool SearchProperties<T>(T part, string searchString) where T : Part
{
var props = typeof(T).GetProperties();
foreach (var prop in props)
{
var value = prop.GetValue(part);
if (value is IEnumerable)
{
// special handling for collections
}
else if(value != null)
{
object searchValue = null;
try
{
searchValue = TypeDescriptor.GetConverter(value).ConvertFromString(searchString);
} catch {}
if (searchValue != null && object.Equals(value, searchValue))
return true;
}
}
return false;
}
TypeDescriptor works well for most built-in types, but requires extra work if you're dealing with custom types.
I think the following should cover the most of the practical scenarios:
public static bool SearchProperties(object target, string searchString)
{
if (target == null) return false;
// Common types
var convertible = target as IConvertible;
if (convertible != null)
{
var typeCode = convertible.GetTypeCode();
if (typeCode == TypeCode.String) return target.ToString() == searchString;
if (typeCode == TypeCode.DBNull) return false;
if (typeCode != TypeCode.Object)
{
try
{
var value = Convert.ChangeType(searchString, typeCode);
return target.Equals(value);
}
catch { return false; }
}
}
if (target is DateTimeOffset)
{
DateTimeOffset value;
return DateTimeOffset.TryParse(searchString, out value) && value == (DateTimeOffset)target;
}
var enumerable = target as IEnumerable;
if (enumerable != null)
{
// Collection
foreach (var item in enumerable)
if (SearchProperties(item, searchString)) return true;
}
else
{
// Complex type
var properties = target.GetType().GetProperties();
foreach (var property in properties)
{
if (property.GetMethod == null || property.GetMethod.GetParameters().Length > 0) continue;
var value = property.GetValue(target);
if (SearchProperties(value, searchString)) return true;
}
}
return false;
}
I will give you one different idea to do it.
You could try something like that:
private bool SearchProperties<T, W>(T part, W searchValue) where T : Part
{
var props = typeof(T).GetProperties();
foreach (var prop in props)
{
if (typeof(W) == prop.PropertyType)
{
var value = prop.GetValue(part, null);
if (searchValue.Equals(value))
return true;
}
}
return false;
}
You need to call the method like this:
private void button12_Click(object sender, EventArgs e)
{
Part p = new Part();
p.Id = 2;
p.Name = "test";
p.bla = new Bla();
SearchProperties<Part, int>(p, 2);
}
And if you need to compare the complex properties (Weight, ...) by a different way from GetHashCode you could override the method Equals or the == operator.
class Weight
{
public int Id { get; set; }
public override bool Equals(object obj)
{
return Id == ((Weight)obj).Id;
}
}
so I'm creating a tree structure with my data and I want to avoid nested nested nested repetition. There can be children within children within children and I need to know what data to make collapsible and give a folder icon. Is there a way to simplify this? Thanks in advance.
foreach (var i in mlist)
{
// if this is a matching child
if (i.key == dto.under.ToString())
{
// add this as a child
i.children.Add(m1);
}
//check children also
foreach (var i2 in i.children)
{
if (i2.key == dto.under.ToString())
{
// add this as a child
i2.children.Add(m1);
}
if (i2.children.Count != 0)
{
i2.folder = true;
}
else
{
i2.folder = false;
}
foreach (var i3 in i2.children)
{
if (i3.key == dto.under.ToString())
{
// add this as a child
i3.children.Add(m1);
}
if (i3.children.Count != 0)
{
i3.folder = true;
}
else
{
i3.folder = false;
}
}
}
if (i.children.Count != 0)
{
i.folder = true;
}
else
{
i.folder = false;
}
}
Here's a recursive example of your current loop
public void Traverse(List<Item> items, Item dto, Item m1)
{
foreach (var i in items)
{
// if this is a matching child
if (i.key == dto.under.ToString())
{
// add this as a child
i.children.Add(m1);
}
i.folder = i.children.Count != 0;
Traverse(i.children, dto, m1);
}
}
...
Traverse(mlist, dto, m1);
You need a recursive function
foreach (var i in mlist)
{
checkChildren(i);
}
and then
void checkChildren( List i ) // i is of type List?
{
if (i.key == dto.under.ToString())
{
// add this as a child
i.children.Add(m1);
// what is m1? you may have to pass
// this in as a parameter. I am not
// really sure what it is
}
if (i.children.Count != 0)
{
i.folder = true;
}
else
{
i.folder = false;
}
foreach (var i2 in i.children)
{
checkChildren(i2);
// this will call the same function again,
// but this time on the next level of your hierarchy
}
}
In my WPF 4.0 project, I have an ObservableCollection that contain some selected Visual3D from the view :
public ObservableCollection<Visual3D> SelectedElements
{
get { return _selectedElements; }
set
{
if (Equals(_selectedElements, value))
{
return;
}
_selectedElements = value;
RaisePropertyChanged(() => SelectedElements);
}
}
Visual3D elements are selected by clicking and the source-code in the VM is :
public HitTestResultBehavior HitTestDown(HitTestResult result)
{
var resultMesh = result as RayMeshGeometry3DHitTestResult;
if (resultMesh == null)
return HitTestResultBehavior.Continue;
// Obtain clicked ModelVisual3D.
var vis = resultMesh.VisualHit as ModelVisual3D;
if (vis != null)
{
Type visType = vis.GetType();
if (visType.Name == "TruncatedConeVisual3D" || visType.Name == "BoxVisual3D")
{
var geoModel = resultMesh.ModelHit as GeometryModel3D;
if (geoModel != null)
{
var selecteMat = geoModel.Material as DiffuseMaterial;
if (selecteMat != null) selecteMat.Brush.Opacity = selecteMat.Brush.Opacity <= 0.7 ? 1 : 0.7;
}
// Otherwise it's a chair. Get the Transform3DGroup.
var xformgrp = vis.Transform as Transform3DGroup;
// This should not happen, but play it safe anyway.
if (xformgrp == null)
{
return HitTestResultBehavior.Stop;
}
// Loop through the child tranforms.
foreach (Transform3D t in xformgrp.Children)
{
// Find the TranslateTransform3D.
var trans =
t as TranslateTransform3D;
if (trans != null)
{
// Define an animation for the transform.
var anima = new DoubleAnimation();
if (trans.OffsetY == 0)
{
DependencyProperty prop = TranslateTransform3D.OffsetZProperty;
if (Math.Abs(trans.OffsetZ) < 2)
{
anima.To = 20.5*Math.Sign(trans.OffsetZ);
Debug.Assert(SelectedElements != null, "SelectedElements != null");
}
else
{
anima.To = 1*Math.Sign(trans.OffsetZ);
SelectedElements.Add(vis);
}
// Start the animation and stop the hit-testing.
trans.BeginAnimation(prop, anima);
return HitTestResultBehavior.Stop;
}
}
}
}
}
return (HitTestResultBehavior) HitTestFilterBehavior.Continue;
}
and I want to delete one or all this Visual3D element
Thank you in advance
I have implemented this methode but it's not work :
private void UnloadProduct()
{
if (CanUnload)
{
foreach (Visual3D selectedElement in SelectedElements)
{
if (selectedElement.DependencyObjectType.Name == "TruncatedConeVisual3D")
{
var test = (TruncatedConeVisual3D) selectedElement;
int id = test.VisualId;
ElementsCollection.RemoveAt(id);
RaisePropertyChanged(() => ElementsCollection);
}
else
{
var test = (BoxVisual3D) selectedElement;
int id = test.VisualId;
ProductsCollection.RemoveAt(id);
}
}
}
}