Creating a property class with no default value and with value - c#

I'm trying to create a property class with a default value and no value. Is this right? If I want a property with no value I'll just call GameLevel class and if I want a property with default value I'll just call GameLevelWithDefaultValue
public abstract class GameLevel
{
public abstract int nextLevelToUnlock { get; set; }
public abstract List<LevelDetails> levelDetails { get; set; }
}
class GameLevelWithDefaultValue : GameLevel
{
public override int nextLevelToUnlock { get; set; } = 1;
public override List<LevelDetails> levelDetails { get; set; } = new List<LevelDetails>()
{
new LevelDetails{levelIndex = 1, Stars = 0 },
new LevelDetails{levelIndex = 2, Stars = 0 },
new LevelDetails{levelIndex = 3, Stars = 0 }
};
}
public class LevelDetails
{
public int levelIndex { get; set; }
public int Stars { get; set; }
}

I meant something like this:
public class GameLevel
{
public int NextLevelToUnlock { get; set; }
public List<LevelDetails> LevelDetails { get; set; }
public GameLevel() { }
public GameLevel(int nextLevelToUnlock, List<LevelDetails> levelDetails)
{
NextLevelToUnlock = nextLevelToUnlock;
LevelDetails = levelDetails;
}
}
public class LevelDetails
{
public int LevelIndex { get; set; }
public int Stars { get; set; }
public LevelDetails(int levelIndex, int stars)
{
LevelIndex = levelIndex;
Stars = stars;
}
}
public static class GameLevelBuilder
{
public static GameLevel BuildGameLevelWithDefaultValue()
{
var defaultLevelDetail = new List<LevelDetails>()
{
new LevelDetails(1, 0),
new LevelDetails(2, 0),
new LevelDetails(3, 0)
};
return new GameLevel(1, defaultLevelDetail);
}
}
When you need the object with the default value, you'll let the GameLevelBuilder create the object for you, while when you need the object without passing the initial values, you'll use the parameterless constructor of GameLevel.

You cannot instantiate an abstract class. If you inherit an abstract class, you must override it's abstract properties. So, the value of nextLevelToUnlock and levelDetails depends on the child class.
Also, default value for class in C# is null, or the result of it's zero parameter constructor for value types. If you don't assign any value to a field, it will get it's default value.

Related

Autofixture: Randomly fill property of a class

Concering the following class:
public partial class ByValueCondition
{
public ParameterCondition ParameterCondition { get; set; }
public TimeOfDayCondition TimeOfDayCondition { get; set; }
public SimulationTimeCondition SimulationTimeCondition { get; set; }
public StoryboardElementStateCondition StoryboardElementStateCondition { get; set; }
public UserDefinedValueCondition UserDefinedValueCondition { get; set; }
public TrafficSignalCondition TrafficSignalCondition { get; set; }
public TrafficSignalControllerCondition TrafficSignalControllerCondition { get; set; }
}
I want a customization in autofixture that will randomly only choose one property and fill it, while leaving the other ones blank. The configuration of the underlying classes should be still defined by the global customizations of the fixture.
Also it should be possible to create a Collection of ByValueCondition.
I tried around with this but cant find an easy solution except creating a ISpecimenbuilder from the ground up.
I would personally do it with following schema:
// Interface implemented by all Conditions
public interface ICondition
{
bool IsConditionTrue(object ObjectThatWeKnow);
}
// Your object
public partial class ByValueCondition
{
public ICondition Condition { get; set; }
}
// And here you define all types of conditions
public class ParameterCondition : ICondition
{
public object Parameter { get; set; }
public bool IsConditionTrue(object ObjectThatWeKnow)
{
return ObjectThatWeKnow.Equals(Parameter);
}
}
public class TimeOfDayCondition : ICondition
{
public bool IsConditionTrue(object ObjectThatWeKnow) { return true; }
}
public class SimulationTimeCondition : ICondition
{
public bool IsConditionTrue(object ObjectThatWeKnow) { return true; }
}
And the randomness you could do as:
var conditions = new List<ICondition>()
{
new ParameterCondition() { Parameter = "whatever" },
new ParameterCondition() { Parameter = "otherString" },
new ParameterCondition() { Parameter = "NextOne" },
new TimeOfDayCondition() { TimeBefore = DateTime.Now },
new TimeOfDayCondition() { TimeAfter = DateTime.Now.AddDays(-1) },
}
var rand = new Random();
var randomN = rand.Next(0, conditions.Count);
var byValueCondition = new ByValueCondition();
byValueCondition.Condition = conditions[randomN]; //Here you assign random value

C# Counting properties of Class with child/nested objects

I have the following construction of classes, here simplified as child classes of a 'mother' class called DataClass, which also contains one simple method:
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public int Count()
{
Type t = typeof(DataClass);
return typeof(DataClass).GetProperties().Length;
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
}
public class SideClass
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
}
The issue is, I want to refactor the method so that it can give me an accurate counting of all properties found, including the ones in nested or child classes. In the above example, it only counts properties of DataClass, while I wanted it to return 2 for DataClass + 2 for PartClass + 1 for MemberClass + 3 for SideClass, sums up to 8 properties you may set through DataClass.
Can someone help me with this?
You can introduce interface with Count() method
public interface ICountable
{
int Count();
}
And use this interface to mark all types, which properties are participating in Count() calculation.
You can see the generic abstract class to implement this interface below. Generic T parameter is type whose properties need to be calculated. You implement a calculation logic only once and inherit this class where needed. You also go through all of properties, implementing ICountable, to calculate them as well (some kind of recursion)
public abstract class Countable<T> : ICountable
{
public int Count()
{
Type t = typeof(T);
var properties = t.GetProperties();
var countable = properties.Select(p => p.PropertyType).Where(p => typeof(ICountable).IsAssignableFrom(p));
var sum = countable.Sum(c => c.GetProperties().Length);
return properties.Length + sum;
}
}
and inherit it in your classes
public class DataClass : Countable<DataClass>
{
...
}
public class PartClass : Countable<PartClass>
{
...
}
public class MemberClass : Countable<MemberClass>
{
...
}
public class SideClass : Countable<SideClass>
{
...
}
And this is for the test
var dataClass = new DataClass();
var count = dataClass.Count();
It returns 8 as expected

C# complex class constructors

I have the following system: a "mother" class called DataClass, has properties and two of them are classes, PartClass and MemberClass. In particular, MemberClass has properties and one of them is a class, SideClass - with its own properties.
Here is the code sample:
using System;
namespace ConsoleApp
{
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
public PartClass part { get; set; }
public MemberClass member { get; set; }
public DataClass()
{
PartClass part = new PartClass();
MemberClass member = new MemberClass();
}
}
public class PartClass
{
public int seriesNum { get; set; }
public string seriesCode { get; set; }
public PartClass() { }
}
public class MemberClass
{
public int versionNum { get; set; }
public SideClass side { get; set; }
public MemberClass()
{
SideClass side = new SideClass();
}
}
public class SideClass
{
public string firstDetail { get; set; }
public string secondDetail { get; set; }
public bool include { get; set; }
public SideClass() { }
}
Now, I am trying to initialize the DataClass and assign values to all properties, and this doesn't work.
So, the DataClass "owns" the PartClass and the MemberClass and the MemberClass itself "sees" the SideClass which is the bottom class and sort of independent of all.
Here the rest of code:
class Program
{
static void Main(string[] args)
{
DataClass myData = new DataClass()
{
num = 13,
code = "message",
//from here downwards nothing works; error..
part.seriesNum = 1,
part.seriesCode = 7,
member.versionNum = 9,
member.side.firstDetail = "pass",
member.side.secondDetail = "checked",
member.side.include = true;
}
}
}
I thought that by installing constructors and properties the DataClass instantiation would not have problems, but actually the DataClass does not see any non-trivial properties (properties referring to classes).
Could someone help me please? Thank you..
Use following :
DataClass myData = new DataClass()
{
num = 13,
code = "message",
part = new PartClass()
{
seriesNum = 1,
//here down nothing works; error
seriesCode = "abc"
},
member = new MemberClass()
{
versionNum = 9,
side = new Side()
{
firstDetail = "pass",
secondDetail = "checked",
include = true
}
}
};
To not have to create the instance of Member Class and Part Class manually every time, you can create the instances using get and set methods.
public class DataClass
{
public int num { get; set; }
public string code { get; set; }
private PartClass _part;
public PartClass part { get { if (_part == null) _part = new PartClass(); return _part; } set { _part = value; } }
private MemberClass _member;
public MemberClass member { get { if (_member == null) _member = new MemberClass(); return _member; } set { _member = value; } }
}
you should create an instance of DataClass then initialize fields
DataClass myData = new DataClass();
myData.num = 13,
myData.code = "message",
myData.part.seriesNum = 1,
myData.part.seriesCode = 7,
myData.member.versionNum = 9,
myData.member.side.firstDetail = "pass",
myData.member.side.secondDetail = "checked",
myData.member.side.include = true;

Automapper - mapping InnerDestination to OuterSource

I've followed the nested example from the Automapper Wiki but I'm having some trouble extending it. In the code below, I'm trying to map InnerDest2 to OuterSource. Specifically, I want InnerDest2.Value to be populated with OuterSource.Value but when I run, InnerDest2 comes back as null. I'm sure there is something simple I'm missing, but I just can't figure it out.
Any ideas?
namespace AutomapNestTest
{
class Program
{
static void Main(string[] args)
{
ConfigureAutomapper();
var source = new OuterSource
{
Value = 5,
Inner = new InnerSource { OtherValue = 15 },
};
var dest = new OuterDest();
AutoMapper.Mapper.Map(source, dest);
}
private static void ConfigureAutomapper()
{
AutoMapper.Mapper.Initialize(cfg =>
{
cfg.CreateMap<OuterSource, OuterDest>();
cfg.CreateMap<InnerSource, InnerDest>();
cfg.CreateMap<OuterSource, InnerDest2>();
});
}
}
public class OuterSource
{
public int Value { get; set; }
public InnerSource Inner { get; set; }
}
public class InnerSource
{
public int OtherValue { get; set; }
}
public class OuterDest
{
public int Value { get; set; }
public InnerDest Inner { get; set; }
public InnerDest2 Inner3 { get; set; }
}
public class InnerDest
{
public int OtherValue { get; set; }
}
public class InnerDest2
{
public int Value { get; set; }
}
}
You are mapping an OuterSource object to an OuterDesc object. There is a mapping configuration from OuterSource to InnerDest2 but there is no property of type OuterSource inOuterSource itself so there is no way for the propertyInner3 in OuterDest to be mapped from anything.
If you need the source.Value to be mapped to dest.Inner3.Value, you would have to do another mapping explicitly. First declare the variable:
var innerDest2 = new InnerDest2();
After this, do the mapping and set the dest.Inner3:
AutoMapper.Mapper.Map(source, innerDest2);
dest.Inner3 = innerDest2;

Match names in list with elements in class

I wonder if there's any way to match the names in a list with the elements in a class:
I have a class:
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
and a List: List<exampleClass> EnfSist
So that's the way the list is made. Now I would like to know how to match or identify the string inside "name" from my list. To match this class:
tbl_sistematicas b = new tbl_sistematicas
{
ap_enf_id_enfermedad = Convert.ToInt32(EnfSist[0].value),
ap_pac_inicio = Convert.ToInt32(EnfSist[1].value),
ap_pac_inicio_periodo = Convert.ToInt32(2].value),
ap_pac_duracion = Convert.ToInt32(EnfSist[3].value),
ap_pac_duracion_periodo = Convert.ToInt32(EnfSist[4].value),
ap_pac_tratamiento = EnfSist[5].value
};
Once being able to match the same names I won't have to specify each index of every element in the list. The elements in the list have the same name as in the table. Not all elements of the class are being used.
I have something like this: tbl_sistematicas bh = EnfSist.FindAll(x => x.name == bh.?????? );
If I understand the question, you can do this using something like automapper or ValueInjector
An example using ValueInjector
void Main()
{
List<exampleClass> EnfSist = new List<exampleClass>();
EnfSist.Add(new exampleClass { name = "ap_enf_id_enfermedad", value = "12" });
EnfSist.Add(new exampleClass { name = "apap_pac_inicio" , value = "34" });
// etc
tbl_sistematicas b = new tbl_sistematicas();
b.InjectFrom<MyInjection>(EnfSist);
}
public class MyInjection : KnownSourceValueInjection<List<exampleClass>>
{
protected override void Inject(List<exampleClass> source, object target)
{
foreach(var entry in source)
{
var property = target.GetProps().GetByName(entry.name, true);
if (property != null)
property.SetValue(target, Convert.ChangeType(entry.value, property.PropertyType));
}
}
}
public class exampleClass
{
public string name { get; set; }
public string value { get; set; }
}
public class tbl_sistematicas
{
public int ap_enf_id_enfermedad { get; set; }
public int apap_pac_inicio { get; set; }
public int ap_pac_inicio_periodo { get; set; }
public int ap_pac_duracion { get; set; }
public int ap_pac_duracion_periodo { get; set; }
public string ap_pac_tratamiento { get; set; }
}
Note, this will throw an exception if the value can not be converted to an int

Categories