Basic question here, but I'm new to c#. I have code that basically says: if condition A, then execute a code block on property X. If condition B, then execute the same code block on property Y, and so on. Instead of having to duplicate my code blocks just to change one single property name - a.Value.ValueX to a.Value.ValueY - is there a way to call ValueX or ValueY as variables, such as a.Value.{$propertyName} ?
public static class Conditions
{
public static bool A { get; set; }
public static bool B { get; set; }
}
public class MyObjects
{
public int ValueX { get; set; }
public int ValueY { get; set; }
}
public class MyCollection
{
public Dictionary<int, MyObjects> listOfObjects = new Dictionary<int, MyObjects>();
public static void DoConditions()
{
foreach( var a in listOfObjects)
{
if(Conditions.A)
{
// do code using value x
if (a.Value.ValueX > 0)
continue;
}
else if(Conditions.B)
{
// do the exact same code using value Y
if (a.Value.ValueY > 0)
continue;
}
}
}
}
You can do this:
int val = 0;
if(Conditions.A)
val = a.Value.ValueX;
else if(Conditions.B)
val = a.Value.ValueY;
// Your code block here using "val".
Create a variable and populate it with the appropriate property value:
foreach( var a in listOfObjects)
{
int value;
if(Conditions.A)
value = a.Value.ValueX;
else
value = a.Value.ValueY;
if(value > 0)
continue;
//other code using `value`
}
Related
I'm new to Entity Framework. I was trying to get my data from my local database through this basic line of code, I wanted to store all of the objects in the "Object" row into a list.
But it seems like it doesn't work, whatever I try. I'm running SQL server, ASP.NET MVC. My code is something like these:
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
result = db.Object.ToList();
// ...
return result;
}
}
It always ended up with "Specified cast is not valid." error:
This is where the error was caught:
Line 137: result = db.Object.ToList();
This is my model class, I added some functions though, but I haven't changed any default properties that Entity set up for me :
public partial class Object
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Like { get; set; }
public int View { get; set; }
public byte Level
{
get { return Level; }
set
{
if (value < 1 || value > 3)
{
Level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
Level = value;
}
}
}
public string Introduction { get; set; }
public string VideoUrl { get; set; }
public string Tag { get; set; }
public string Steps { get; set; }
public DateTime Date { get; set; }
public Object(string name, byte level, string introduction = null)
{
this.Name = name;
this.Level = level;
this.Introduction = introduction;
}
}
Is it oke to add functions and fix the properties like that ??
This is my table design in sql : pic
You have used public byte Level auto-property with a custom setter method.
This should be accompanied with a private backing variable. Something like
private byte _level
public byte Level
{
get { return _level; }
set
{
if (value < 1 || value > 3)
{
_level = 1;
throw new Exception("Level must be in 1 to 3. By default, it becomes 1");
}
else
{
_level = value;
}
}
}
You need to case the Object into a specific Model object something like this
[HttpGet]
public List<Object> Function1()
{
List<Object> result = new List<Object>();
using (DatabaseContext db = new DatabaseContext())
{
//result = db.Object;
result = (from d in db.Object.ToList()
select new Object{
prop1 = d.prop1,
prop2 = d.prop2,
.......
}).ToList();
// ...
return result;
}
}
I am trying to implement object deep/shallow cloning service using Reflection.
Using the function Clone<T> Simple class is being copied with all the required fields, but in case of SimpleStruct Computed field does not get copied.
What is the difference between struct and class when defining read-only fields, and how this can be solved ?
Thanks in advance.
public T Clone<T>(T source)
{
var obj = Activator.CreateInstance<T>();
var type = source.GetType();
foreach (var property in type.GetProperties())
{
if (!property.IsValid())
continue;
if (property.SetMethod != null)
{
property.SetValue(obj, property.GetValue(source));
}
}
foreach (var field in type.GetFields())
{
if (field.IsPublic == false || !field.IsValid())
continue;
field.SetValue(obj, field.GetValue(source));
}
return obj;
}
public struct SimpleStruct
{
public int I;
public string S { get; set; }
[Cloneable(CloningMode.Ignore)]
public string Ignored { get; set; }
public string Computed => S + I;
public SimpleStruct(int i, string s)
{
I = i;
S = s;
Ignored = null;
}
}
public class Simple
{
public int I;
public string S { get; set; }
[Cloneable(CloningMode.Ignore)]
public string Ignored { get; set; }
[Cloneable(CloningMode.Shallow)]
public object Shallow { get; set; }
public string Computed => S + I + Shallow;
}
I have this class:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get; set; }
}
and a list
List<Test> myTestList;
How can I make the value of the field DoubleNumber in myTestList equal to twice the value of Number? Note that I am okay to create another list if that's needed.
If I understand your question correctly:
foreach(Test item in myList) {
item.DoubleNumber = 2*item.Number;
}
Or, if it's ok, just remove the setter and modify the getter to return 2x Number:
public class Test
{
public string Id { get; set; }
public int Number { get; set; }
public int DoubleNumber { get { return 2* this.Number; } } //completely remove setter
}
Or, if you still want to be able to modify DoubleNumber:
public class Test {
private int m_num;
private int m_doubleNum;
public string Id {
get;
set;
}
public int Number {
get {
return this.m_num;
}
set {
this.m_num = value;
this.m_doubleNum = 2 * value; //when Number is set, update m_doubleNum too
}
}
public int DoubleNumber {
get {
return this.m_doubleNum;
}
set {
this.m_doubleNum = value; //allow manual setting of DoubleNumber
//or maybe also modify Number here?
//this.m_num = value / 2;
}
}
}
One way it could be using a foreach statement:
foreach(var item in myTestList)
{
item.DoubleNumber = 2*item.Number;
}
Another way it could be to use LINQ.
var result = myTestList.Select(test => new Test
{
test.Id,
test.Number,
DoubleNumber = 2*test.Number;
})
.ToList();
Among the two ways I would prefer the first one, since it's more clear what you are trying to do and more performant (in the second approach you have to create a new object for each object in myTestList).
I have the following class properties:
[EffectAspect(Enums.Effects.Low)]
public int Wind { set; get; }
[EffectAspect(Enums.Effects.Low)]
public int Fire { set; get; }
[EffectAspect(Enums.Effects.Medium)]
public int Water { get; set; }
[EffectAspect(Enums.Effects.Huge)]
public int Earth { get; set; }`
Now, let's say I want to calculate the total Lows, Mediums and Huges.
So I wrote something like:
List<Enums.Effects> result = new List<Enums.Effects>();
PropertyInfo[] properties = GetType().GetProperties();
foreach (PropertyInfo p in properties)
{
object[] attrs = p.GetCustomAttributes(true);
foreach (Object attr in attrs)
{
var effectAttr = attr as EffectAspect;
if (effectAttr != null)
{
int amount = (int)p.GetConstantValue();
for (int i = 0; i < amount; i++)
{
result.Add(effectAttr.Aspect);
}
}
}
}
return result;
For example: if Wind = 3, there would be at least 3 Enums.Effects.Low inside the result list.
[AttributeUsage(AttributeTargets.Property)]
public sealed class EffectAspectAttribute : Attribute
{
public Enums.EffectsAspect { get; private set; }
public EffectAspectAttribute (Enums.EffectsAspect aspect)
{
this.Aspect = aspect;
}
}
The problems is: int amount = (int)p.GetConstantValue(); throws exceptions says:
Literal value was not found.
And I couldn't find what it means.
You can try to use
p.GetValue(this, null)
instead of
p.GetConstantValue();
You can refer this link thread: Difference between GetValue, GetConstantValue and GetRawConstantValue
Is it possible to add a log to the destination object, when using AutoMapper?
If I have two objects:
class A
{
int PropertyOne
int PropertyTwo
int PropertyThree
List<string> Log
}
class B
{
int PropertyOne
int PropertyTwo
}
When mapping from B to A, I'd like to automatically have a log entry added to A.Log for every property that is changed.
E.g. if during a mapping operation, PropertyOne = 3 on both objects, but A.PropertyTwo = 1 and B.PropertyTwo = 2, I'd like to have a log entry added to A.Log - preferably something like "PropertyTwo changed from 1 to 2"
Instead of an auto-property, create a property with a custom setter in which you add an entry to the log list.
Example console application:
public static class Program
{
public class A
{
private int _PropertyOne;
private int _PropertyTwo;
private int _PropertyThree;
public int PropertyOne
{
get { return _PropertyOne; }
set
{
if (value == _PropertyOne)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyOne, value));
_PropertyOne = value;
}
}
public int PropertyTwo
{
get { return _PropertyTwo; }
set
{
if (value == _PropertyTwo)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyTwo, value));
_PropertyTwo = value;
}
}
public int PropertyThree
{
get { return _PropertyThree; }
set
{
if (value == _PropertyThree)
return;
Log.Add(string.Format("PropertyOne changing value from {0} to {1}", _PropertyThree, value));
_PropertyThree = value;
}
}
public List<string> Log { get; private set; }
public A()
{
Log = new List<string>();
}
}
public class B
{
public int PropertyOne { get; set; }
public int PropertyTwo { get; set; }
}
public static void Main(string[] args)
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<A, B>().ReverseMap();
});
var b = new B() {PropertyOne = 1, PropertyTwo = 2};
var a = AutoMapper.Mapper.Map<B, A>(b);
a.Log.ForEach(s => Console.WriteLine(s));
}
}
This will output:
PropertyOne changing value from 0 to 1
PropertyTwo changing value from 0 to 2
You could implement a custom type converter that would work with a marker interface called IPropertyLogger. Any subtype of that could be explicitly used by AutoMapper.
The type converter could use reflection and perform the diff-like operation you are requesting before calling default AutoMapper behavior. This would work for all tagged types and you would not have to code each object specifically for the case.
Your reflection based diff code would handle all of the logging you require keeping you objects clean from implementation code.