Nested Class <List> : how to access nested class in list? - c#

Basically i have one class with subclass(or nested class, inner class whatever it gets called)
I have no idea why i cant access (or list doesnt include nested class i guess)
nested class.
public static List<Tag> Tags = new List<Tag>();
//cureently selected tag,also random percentage related data
public class Tag
{
public string name = null;
public int dupe = 0;
public int Tagindex = 0;
public int URLindex = 0;
public class Type
{
public bool isArtist = false;
public bool isGroup = false;
public bool isTag = false;
public bool isURL = false;
}
public class Score
{
// 0~10, sort them out!
public bool isRated = false; //make true if user modifies score
public int Story = 0;
public int Reality = 0;
public int Drawing = 0;
public int memetic = 0;
public string msg = null;
}
dataGridView1.Rows.Add(gVar.Tags[i].Tagindex,gVar.Tags[i].name/*valid*/, gVar.Tags[i].Type.isArtist/*invalid*/);
//also invalid
Tag t1 = new Tag();
t1.Type.isArtist = true;
gVar.Tags.Add(t1);

The nested class is just a declaration of the class, same as if that class was not nested.
You have to instantiate an object of that type in order to access one of its properties.
For example:
public class Tag
{
public string name = null;
public int dupe = 0;
public int Tagindex = 0;
public int URLindex = 0;
public Score Score { get; } = new Score() // declare a property of the nested type, and instantiate an object
public class Type
{
public bool isArtist = false;
public bool isGroup = false;
public bool isTag = false;
public bool isURL = false;
}
public class Score
{
// 0~10, sort them out!
public bool isRated = false; //make true if user modifies score
public int Story = 0;
public int Reality = 0;
public int Drawing = 0;
public int memetic = 0;
public string msg = null;
}
And the usage:
Tag t1 = new Tag();
t1.Score.Story = 3;
By the way, it's not recommended to use public fields, use properties instead (such as the Score property in the code above).

Related

binding a list of class to a data grid UWP

I would like to display this object(Node) in a data grid (coordinate is a custom class that literally describes a coordinate) -
public class Node
{
[JsonRequired]
private bool finished;
[JsonRequired]
private readonly string type;
[JsonRequired]
private coordinate starting_point = null;
[JsonRequired]
private string ID = "";
[JsonRequired]
public coordinate Final_Dest = null;
[JsonRequired]
public List<coordinate> check_points = new List<coordinate>();
[JsonRequired]
private string Metadata = "";
[JsonRequired]
private readonly SimpleMarkerSymbol symbol;
[JsonRequired]
private int Vmax;
[JsonRequired]
public int Amax;
[JsonRequired]
private int slope_max;
[JsonRequired]
private int slope_min;
[JsonRequired]
private int terrein_rank_reject;
[JsonRequired]
private int affinity_to_stay_in_group;
[JsonRequired]
public int GroupID;
[JsonRequired]
public bool coomplitionflag = false;
this is what I tried to do -
protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);
selected_nodes = (comboclass)e.Parameter;
postioning_index = selected_nodes.Get_index();
Node[] array_of_nodes = selected_nodes.Get_node_array();
dataGrid.ItemsSource = Create_list(array_of_nodes);//this function creates a list of nodes
}
public static List<Node> Create_list(Node[] array_nodes)
{
var node_coll = new List<Node>();
for (int i = 0; i < array_nodes.Length; i++)
{
node_coll.Add(array_nodes[i]);
}
return node_coll;
}
and for some reason when I execute it only shows the field -type on the data grid
binding a list of class to a data grid UWP
If you want to bind the Node instance, you need implement the public field's set get method.
Please edit your class like the following.
public class Node
{
public string Title { get; set; }
public coordinate Final_Dest { get; set; }
.......
}
For more detail please refer Data binding in depth document.

Exposing fields in a class

I am new to c# and object coding so please be gentle....
I have a class call LED, see below:
public sealed class LED
{
public GpioPinValue ReqPinValue { get; set; } //Enable/Disable LED
public bool Flashing { get; set; } //Does the LED flash
public GpioPin Pin { get; set; }
public int flashingPeriod { get; set; } //Period to flash in seconds
private GpioPinValue value; //Pin value (high/low)
private int flashCount = 0; //Times we have entered the timer loop
public LED()
{
}
public void UpdateLED()
{
int timesToCycle = 0;
if (ReqPinValue == GpioPinValue.Low)
{
if (Flashing)
{
timesToCycle = flashingPeriod * 2;
if (flashCount == timesToCycle)
{
value = (value == GpioPinValue.High) ? GpioPinValue.Low : GpioPinValue.High;
Pin.Write(value);
flashCount = 0;
}
else
flashCount++;
}
else
{
Pin.Write(GpioPinValue.Low);
}
}
else
{
Pin.Write(GpioPinValue.High);
}
}
}
In another class I create four instances of this LED class for 4 different Status LED'S.
public sealed class StatusLED
{
private const int RUN_LED = 4;
private const int IO_LED = 17;
private const int NET_LED = 27;
private const int FAULT_LED = 22;
public LED RunLed = new LED();
public LED IOLed = new LED();
public LED NetLed = new LED();
public LED FaultLed = new LED();
private GPIO GPIO = new GPIO();
private GpioController gpioController;
private ThreadPoolTimer timer;
public void InitStatusLED()
{
gpioController = GPIO.InitGPIO();
if (gpioController == null)
{
Debug.WriteLine("Failed to find GPIO Controller!");
//TODO proper error handling although this should never happen
}
else
{
//Setup the default parameters for the LEDS (ie flashing or non-flashing)
RunLed.Flashing = false;
IOLed.Flashing = false;
NetLed.Flashing = false;
FaultLed.Flashing = false;
RunLed.flashingPeriod = 0;
IOLed.flashingPeriod = 0;
NetLed.flashingPeriod = 0;
FaultLed.flashingPeriod = 0;
RunLed.Pin = GPIO.InitOutputPin(gpioController, RUN_LED);
IOLed.Pin = GPIO.InitOutputPin(gpioController, IO_LED);
NetLed.Pin = GPIO.InitOutputPin(gpioController, NET_LED);
FaultLed.Pin = GPIO.InitOutputPin(gpioController, FAULT_LED);
//Turn the LED's on to Start
RunLed.ReqPinValue = GpioPinValue.Low;
IOLed.ReqPinValue = GpioPinValue.Low;
NetLed.ReqPinValue = GpioPinValue.Low;
FaultLed.ReqPinValue = GpioPinValue.Low;
timer = ThreadPoolTimer.CreatePeriodicTimer(Timer_Tick, TimeSpan.FromMilliseconds(500));
}
}
private void Timer_Tick(ThreadPoolTimer timer)
{
RunLed.UpdateLED();
IOLed.UpdateLED();
NetLed.UpdateLED();
FaultLed.UpdateLED();
}
}
I now want to set the field "ReqPinValue" for these instances in the StatusLED class from another class using the code below
private StatusLED statusLED = new StatusLED();
statusLED.RunLed.ReqPinValue = GpioPinValue.Low;
I get the following error:
Error: Type '....' contains externally visible field '....' Fields
can be exposed only by structures.
I can see it doesn't like the line below being public, how can I can access a parameter of this instance from another class without making it public?
public LED RunLed = new LED();
You can make these properties rather than fields:
public LED RunLed {get;set;}
public LED IOLed {get;set;}
public LED NetLed {get;set;}
public LED FaultLed {get;set;}
Then, in your InitStatusLED method, initialize them:
public void InitStatusLED()
{
gpioController = GPIO.InitGPIO();
if (gpioController == null)
{
Debug.WriteLine("Failed to find GPIO Controller!");
//TODO proper error handling although this should never happen
}
else
{
//Setup the default parameters for the LEDS (ie flashing or non-flashing)
RunLed = new LED(GPIO.InitOutputPin(gpioController, RUN_LED));
IOLed = new LED(GPIO.InitOutputPin(gpioController,IO_LED));
//And so on
But wait - your LED class doesn't have a constructor that accepts a GpioPin. Let's fix that too:
public sealed class LED
{
public GpioPinValue ReqPinValue { get; set; } //Enable/Disable LED
public bool Flashing { get; set; } //Does the LED flash
public GpioPin Pin { get; set; }
public int flashingPeriod { get; set; } //Period to flash in seconds
private GpioPinValue value; //Pin value (high/low)
private int flashCount = 0; //Times we have entered the timer loop
public LED(GpioPin pin)
{
Pin = pin;
Flashing = false;
flashingPeriod = 0;
ReqPinValue = GpioPinValue.Low;
}
And see how we've eliminated a whole load of repetitive code from you InitStatusLed method too.
Having done all of this, go back and look at your properties again. For those which should only be set by the class itself, and not by any other code using the class, make the setters private:
public GpioPin Pin { get; private set; }

Getting keyvaluepair values dynamically

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`
}

how to add constructors parameter to a list?

I got a list of classes called classList. Each class in this list has a constructor with a string parameter that contains some info about the class. I want to iterate through the classList and then add all the constructor parameters to a stringarray.
How can I do this?
public Main()
{
classList = new List<class>();
class1 = new class1("class1 information");
class2 = new class2("class2 information");
classList.Add(class1);
classList.Add(class2);
}
public void getConstructorParametersToList()
{
string[] myArrayList = null;
for(int i = 0; i < classList.Count; i++)
{
//Add the parameters from the constructors to a string array
myArrayList[i] = parameterfromconstructor
}
}
public void doSomething()
{
foreach (string s in myArrayList)
{
Console.WriteLine(s);
}
}
//Output:
//Class1 information
//Class2 information
You can store that constructor parameter in class field or property and later access it.
public interface IParameterizedClass
{
string ClassParameter {get}
}
public class class1 : IParameterizedClass
{
public string ClassParameter {get; private set;}
public class1(string someParameter)
{
// do some work
ClassParameter = someParameter;
}
}
public class class2 : IParameterizedClass
{
public string ClassParameter {get; private set;}
public class2(string someParameter)
{
// do some work
ClassParameter = someParameter;
}
}
public void getConstructorParametersToList()
{
string[] myArrayList = null;
for(int i = 0; i < classList.Count; i++)
{
//Add the parameters from the constructors to a string array
myArrayList[i] = (classList[i] as IParameterizedClass).ClassParameter;
}
}

Detecting changes within serializable data classes in C#

I've been experimenting with detecting changes in plain objects in C#. The aim being to have a container-type class for a bunch of data objects that can react when any one of them changes. For fun I wanted to see if all the work could be done in the container class, rather than resort to properties and dirty flags or events on the objects themselves.
What I'm curious about is whether there is a smart, fast and efficient way of doing this. My attempt is below, and it's none of those (the 'CheckStates' method would need to be called every frame for a start!) I've restricted it to only allow one instance per type, which suits my needs.
Note that an object passed in might be as follows:
[Serializable]
public class PlayerInfo
{
public string name = string.Empty;
public int score = 0;
}
Then the container:
public class AppState
{
private class StateData
{
public System.Object instance = null;
public Byte[] currentState = new Byte[0];
public Byte[] previousState = new Byte[0];
}
private Dictionary<Type, StateData> _allStates = new Dictionary<Type, StateData>();
private BinaryFormatter _formatter = new BinaryFormatter();
private MemoryStream _memoryStream = new MemoryStream();
public T GetState<T>() where T : class, new()
{
T state = default(T);
var stateType = typeof(T);
StateData stateData;
if(_allStates.TryGetValue(stateType, out stateData))
{
state = ReadData<T>(stateData);
}
else
{
var newState = CreateData<T>(out state);
_allStates[stateType] = newState;
}
return state;
}
public void CheckStates()
{
foreach(var state in _allStates)
{
if(HasChanged(state.Value))
{
Console.WriteLine(state.Key.ToString() + " has changed");
UpdateState(state.Value);
}
}
}
private StateData CreateData<T>(out T instance) where T : class, new()
{
instance = new T();
var stateData = new StateData();
stateData.instance = instance;
_formatter.Serialize(_memoryStream, instance);
var bytes = _memoryStream.ToArray();
stateData.currentState = bytes;
stateData.previousState = bytes;
return stateData;
}
private T ReadData<T>(StateData data) where T : class, new()
{
return data.currentState as T;
}
private bool HasChanged(StateData data)
{
_memoryStream.Position = 0;
_formatter.Serialize(_memoryStream, data.instance);
var current = _memoryStream.ToArray();
var previous = data.previousState;
if(current.Length != previous.Length)
{
return true;
}
for(int i = 0; i < current.Length; ++i)
{
if(current[i] != previous[i])
{
return true;
}
}
return false;
}
private void UpdateState(StateData data)
{
_memoryStream.Position = 0;
_formatter.Serialize(_memoryStream, data.instance);
data.previousState = _memoryStream.ToArray();
}
}
Alternatives I could think of were:
use structs instead of serializable classes (being forced to pass by value would mean that any change would have to go through a 'set' method on the container)
have the AppState's 'GetState' method return an IDisposable wrapper, which on Dispose could trigger a check for changes on that type (only problem is that there's nothing to stop someone from storing a reference to the object and modifying it without the container knowing)
EDIT: should add that it doesn't need to be thread-safe
I don't regard serializable classes as POCO, because you're engineering the classes so that they work with your change detection mechanism. So I wouldn't call them plain.
Your alternatives:
use structs instead of serializable classes
Don't use mutable structs Why are mutable structs “evil”?. And if your struct is immutable, then you might as well pass by reference, i.e. have a class.
have the 'get' method return an IDisposable wrapper
I'm not sure what get method you are referring to.
Proxy
One alternative is to allow a descendant proxy to react to calls to the setters:
public class PlayerInfo
{
public virtual string Name { get; set; }
public virtual int Score { get; set; }
}
public class PlayerInfoDetection : PlayerInfo
{
public int Revision { get; private set; }
public override string Name
{
set
{
base.Name = value;
Revision++;
}
}
public override int Score
{
set
{
base.Score = value;
Revision++;
}
}
}
private static void Example()
{
PlayerInfo pi = new PlayerInfoDetection();
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
pi.Name = "weston";
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
pi.Score = 123;
Console.WriteLine(((PlayerInfoDetection)pi).Revision);
}
This is how NHibernate "watches" objects fetched from the database, and why every object property must be virtual in NHibernate.
Aspect orientated
The same could be achieved with a product like post sharp where you could annotate your class to tell it when the revision must be changed.
public class PlayerInfo
{
public int Revision { get; private set; }
public string Name { get; [IncreaseRevision] set; }
public int Score { get; [IncreaseRevision] set; }
}
Making use of a well implemented hash function
Hash functions should not change their value while the object is in a container such as a hash set. We can make use of this to detect changes.
Drawback Note that any Hash collisions will yield incorrect results. This includes duplicates.
[TestClass]
public class ChangeDetectUnitTest
{
public class ChangeDetectList<T>
{
private readonly List<T> list = new List<T>();
private readonly ISet<T> hashes = new HashSet<T>();
public bool HasChanged(T t)
{
return !hashes.Contains(t);
}
public void Add(T t)
{
list.Add(t);
hashes.Add(t);
}
public void Reset()
{
hashes.Clear();
foreach (var t in list)
hashes.Add(t);
}
}
public class PlayerInfo
{
public string Name { get; set; }
public int Score { get; set; }
public override int GetHashCode()
{
//every field that you want to detect must feature in the hashcode
return (Name ?? "").GetHashCode() * 31 + Score;
}
public override bool Equals(object obj)
{
return Equals(obj as PlayerInfo);
}
public bool Equals(PlayerInfo other)
{
if (other == null) return false;
return Equals(other.Name, Name) && Score == Score;
}
}
private ChangeDetectList<PlayerInfo> list;
[TestInitialize]
public void Setup()
{
list = new ChangeDetectList<PlayerInfo>();
}
[TestMethod]
public void Can_add()
{
var p1 = new PlayerInfo();
list.Add(p1);
Assert.IsFalse(list.HasChanged(p1));
}
[TestMethod]
public void Can_detect_change()
{
var p1 = new PlayerInfo();
list.Add(p1);
p1.Name = "weston";
Assert.IsTrue(list.HasChanged(p1));
}
[TestMethod]
public void Can_reset_change()
{
var p1 = new PlayerInfo();
list.Add(p1);
p1.Name = "weston";
list.Reset();
Assert.IsFalse(list.HasChanged(p1));
}
}

Categories