C# - Newly created variable of custom class does not exist - c#

I created a new class called DashObject, then immediately created an example DashObject. But when I try to access it, the IDE says it doesn't exist.
I'm trying to manage Amazon Dash devices using this class, but I can't even access them once defined for some reason.
class DashObject
{
// Definitions
string DashName;
string DashIdentifier;
int DashFunction;
string DashFunctionInfo;
// Constructor
public DashObject(string dashName, string dashIdentifier, int dashFunction, string dashFunctionInfo)
{
DashName = dashName;
DashIdentifier = dashIdentifier;
DashFunction = dashFunction;
DashFunctionInfo = dashFunctionInfo;
}
}
//Create example DashObject
DashObject example = new DashObject("Example", "44650DFD85E9", 1, "prsl");
//Attempt to access example (this line causes build to fail)
MessageBox.Show(example.DashName);

Make sure you have a public or internal access modifier on it. Change your code to:
public class DashObject
{
// Definitions
public string DashName;
public string DashIdentifier;
public int DashFunction;
public string DashFunctionInfo;
// Constructor
public DashObject(string dashName, string dashIdentifier, int dashFunction, string dashFunctionInfo)
{
DashName = dashName;
DashIdentifier = dashIdentifier;
DashFunction = dashFunction;
DashFunctionInfo = dashFunctionInfo;
}
}

in order to access the field you must set it to public or internal:
public string DashName;
or
internal string DashName;

Related

dynamic .ToObject<CustomClass>() not working as expected

I have a .json file and a custom class.
I am taking this .json file and putting it in a dynamic variable, so that I can access specific points in the file at run time. See below code
private static dynamic elements = null;
public static dynamic Elements { get { return elements; } }
static Settings()
{
elements = JObject.Parse(Common.GetFile("Elements.json"));
}
In the below function, I am using the dynamic variable above in order to identify smaller "chunks" of the .json file. [See Below]
public void Login(string pUserName, string pPassword)
{
dynamic _module = Settings.Elements.Login;
ElementObject _userName = _module.UserName.ToObject<ElementObject>();
ElementObject _password = _module.Password.ToObject<ElementObject>();
ElementObject _loginBTN = _module.LoginButton.ToObject<ElementObject>();
_userName.OnSendKeys(pUserName);
_password.OnSendKeys(pPassword);
_loginBTN.OnClick();
}
The issue, is that ElementObject.cs has a constructor that requires the public properties to be populated via the .json script. However, when stepping through debugging, the public properties arn't getting set until after the variable declaration. [See images below]
public class ElementObject
{
public string ClassName;
public string CssSelector;
public string Id;
public string LinkText;
public string Name;
public string PartialLinkText;
public string TagName;
public string XPath;
private int index = 0;
private string finalName = "";
private string finalClassName = "";
public ElementObject()
{
var _b = new string[] { nameof(ClassName), nameof(CssSelector), nameof(Id), nameof(LinkText), nameof(Name), nameof(PartialLinkText), nameof(TagName), nameof(XPath) };
var _a = new string[] { ClassName, CssSelector, Id, LinkText, Name, PartialLinkText, TagName, XPath };
index = Array.IndexOf(_a, _a.FirstOrDefault(s => !string.IsNullOrEmpty(s)));
finalName = _a[index];
finalClassName = _b[index];
}
}
In the picture below, you can see that I am properly getting the json data.
In the below picture, by the time we get to the constructor, none of the values are being populated
In the below picture, you can see that after we stepped out of the constructor, the properties were applied, but the constructor didn't see it applied.
I created a work around, after investigation what I wanted doesn't seem to work.
Here is my work around. [See Code Below].
public ElementObject() { }
public static ElementObject Create(dynamic pSrcObj)
{
ElementObject obj = pSrcObj.ToObject<ElementObject>();
obj.Init();
return obj;
}
public void Init()
{
var _b = new string[] { nameof(ClassName), nameof(CssSelector), nameof(Id), nameof(LinkText), nameof(Name), nameof(PartialLinkText), nameof(TagName), nameof(XPath) };
var _a = new string[] { ClassName, CssSelector, Id, LinkText, Name, PartialLinkText, TagName, XPath };
index = Array.IndexOf(_a, _a.FirstOrDefault(s => !string.IsNullOrEmpty(s)));
finalName = _a[index];
finalClassName = _b[index];
}
In order for me now to create the object, i create it like this;
ElementObject _userName = ElementObject.Create(_module.UserName);

How can categorize properties in a class?

Assume we want to define a class that contains all constants that we will use in our solution. And this class doesn't have any methods.
public class _const
{
/// Group1: 'DataBase'. We naming "db" group
public const Server_Name = 'ServerName';
public const DB_Name = 'DBName';
public const DB_User = 'UserName';
public const DB_Password = 'Password';
/// Group2: 'Default Variable'. We naming "default" group
public const Title= 'DefaultTitle';
public const KeyWord = 'DefaultKeyWord';
/// Group3: 'Status' constans.We naming "status" group
public const Approved = 'Approved';
public const Rejected = 'Rejected';
public const Suspended = 'Suspended';
/// And so on...
/// ...
/// ...
/// ...
}
We know, these constants will be used anywhere in the solution simply with below instruction. And don't need to create an instance of the class.
/// For example:
string x = _const.Approved;
My question is: for easier use and more code readability, is there any way for grouping related constant together? And access to each group with own prefix name (like namespace)?
Something similar to the following code.
/// For example:
string x = _const.db.DB_Name;
string y = _const.default.KeyWord;
string z = _const.status.Approved;
I think a mix of Enum and Dictionary could help you since, though with a little more verbose call, it assures consistency throughout your code:
public enum Db
{
Server_Name,
DB_Name,
DB_User,
DB_Password,
}
public enum Default
{
Title,
Keyword
}
public enum Status
{
Approved,
Rejected,
Suspened
}
public static class _const
{
public static Dictionary<Db, string> db = new Dictionary<Db, string>()
{
{Db.Server_Name, "ServerName"},
{Db.DB_Name, "DBName"},
{Db.DB_User, "UserName"},
{Db.DB_Password, "Password"}
};
public static Dictionary<Default, string> defaults = new Dictionary<Default, string>()
{
{Default.Title, "DefaultTitle"},
{Default.Keyword, "DefaultKeyWord"}
};
public static Dictionary<Status, string> status = new Dictionary<Status, string>()
{
{Status.Approved, "Approved"},
{Status.Rejected, "Rejected"},
{Status.Suspened, "Suspended"}
};
}
that you can use in your code like:
string string_x = _const.db[Db.Server_Name];
string string_y = _const.defaults[Default.Keyword];
string string_z = _const.status[Status.Suspened];
You can make your class static and define another nested static class like this:
public static class Constants
{
public static class Group1
{
internal const string String1 = "String1";
}
}
internal class Program
{
internal static void Main()
{
Console.WriteLine(Constants.Group1.String1);
}
}

Looping to Create and Add New Objects to ArrayList

Edit to save you from reading through this whole post
tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field
I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:
create ArrayList of Blogs
loop (some condition)
create new Blog
add this Blog to AL
However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:
public static ArrayList AllBlogs()
{
SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");
ArrayList allBlogs = new ArrayList();
if (dr.HasRows)
{
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
}
dr.Close();
return allBlogs;
}
As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?
Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:
Blog object has id, title, and message fields and their respective getter/setters
Kristina_Blogs is a table representing these blogs with columns for id, title, message
The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
This code works perfectly when I use an ArrayList of Strings instead of Blogs
Edit: Including the code from Blog class
public class Blog
{
public App myApp;
public static string Title;
public static string Message;
public static int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public string getTitle() { return Title; }
public void setTitle(string t) { Title = t; }
}
The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:
public class Blog
{
public int Id { get; set; }
public string Title { get; set; }
public string Message { get; set; }
}
And fill your list this way, don't forget to add using System.Linq;:
var result = new List<Blog>();
var connection = #"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();
//Get data
adapter.Fill(dataTable);
dataTable.Rows.Cast<DataRow>().ToList()
.ForEach(row =>
{
var b = new Blog();
b.Id = row.Field<int>("Id");
b.Title = row.Field<string>("Title");
b.Message = row.Field<string>("Message");
result.Add(b);
});
return result;
Note:
When you create a member static, it is shared between all instances of that calss.
In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:
Property:
private int id;
public int Id
{
get
{
return id;
}
set
{
id = value;
}
}
or more simple:
public int Id { get; set; }
All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.
Remove the static attributes from your class:
public class Blog
{
public App myApp;
public String Title;
public String Message;
public int Id;
//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }
//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }
}
When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.
Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.
I would make a quick method to prevent null value from throwing error
public static string GetSafeString(SqlDataReader reader, int index)
{
if (!reader.IsDBNull(index))
return reader.GetString(index);
else
return string.Empty;
}
Replace this code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setTitle(dr["title"].ToString());
b.setMessage(dr["message"].ToString());
b.setId(dr["id"]);
allBlogs.Add(b);
}
With This Code:
while (dr.Read())
{
Blog b = new Blog();
//grab a row from Kristina_Blogs and assign those attributes to b
b.setId(dr.GetInt32(0));
b.setTitle(GetSafeString(dr, 1);
b.setMessage(GetSafeString(dr, 2);
allBlogs.Add(b);
}
Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.

Read values from a non-delimited string into class object

I have a string with the following structure:
Student Name________AgeAddress_______________________Bithday___Lvl
Example:
Jonh Smith 016Some place in NY, USA 01/01/2014L01
As you can see, there is no delimited character like | or ,
Also, there is no space between fields (if you check, there is no space between Age/Address and Birthday/Level.
The size of each field is static so if data's length is less then it will contains white spaces.
I have a class that need to be filled with that information:
public class StudentData
{
public char[] _name = new char[20];
public string name;
public char[] _age = new char[3];
public string age;
public char[] _address = new char[30];
public string address;
public char[] _bday = new char[10];
public string bday;
public char[] _level = new char[3];
public string level;
}
Is there any way to do this automatically and dynamically?
I mean I really don't want to code like this:
myClass.name = stringLine.substring(0,19);
myClass.age = stringLine.substring(20,22);
That's because I have way more fields that the ones added in this example & way more string lines with other different data.
Update: There were supposed to be a lot of spaces between "Smith" and "016", but I don't know how to edit it.
Update2: If I use StringReader.Read() I can evade to use substring and indexes, but it isn't still so dynamically because I would need to repeat those 3 lines for each field.
StringReader reader = new StringReader(stringLine);
reader.Read(myClass._name, 0 myClass._name.Length);
myClass.name = new string(myClass._name);
Given your requirement I came up with an interesting solution. All be-it it may be more complex and longer than using the String.SubString() method as stated.
However this solution is transferable to other types and other string. I used a concept of Attributes, Properties, and Reflection to parse a string by a Fixed Length and setting the class Properties.
Note I did change your StudentData class to follow a more conventional coding style. Following this handy guide on MSDN: http://msdn.microsoft.com/en-us/library/xzf533w0(v=vs.71).aspx
Here is the new StudentData class. Note it uses the properties as opposed to fields. (Not discussed here).
public class StudentData
{
string name;
string age;
string address;
string bday;
string level;
[FixedLengthDelimeter(0, 20)]
public string Name { get { return this.name; } set { this.name = value; } }
[FixedLengthDelimeter(1, 3)]
public string Age { get { return this.age; } set { this.age = value; } }
[FixedLengthDelimeter(2, 30)]
public string Address { get { return this.address; } set { this.address = value; } }
[FixedLengthDelimeter(3, 10)]
public string BDay { get { return this.bday; } set { this.bday = value; } }
[FixedLengthDelimeter(4, 3)]
public string Level { get { return this.level; } set { this.level = value; } }
}
Note on each of the properties there is an Attribute called FixedLengthDelimeter that takes two parameters.
OrderNumber
FixedLength
The OrderNumber parameter denotes the order in the string (not the position) but the order in which we process from the string. The second parameter denotes the Length of the string when parsing the string. Here is the full attribute class.
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public sealed class FixedLengthDelimeterAttribute : Attribute
{
public FixedLengthDelimeterAttribute(int orderNumber, int fixedLength)
{
this.fixedLength = fixedLength;
this.orderNumber = orderNumber;
}
readonly int fixedLength;
readonly int orderNumber;
public int FixedLength { get { return this.fixedLength; } }
public int OrderNumber { get { return this.orderNumber; } }
}
Now the attribute is simple enough. Accepts the two paramters we discussed eariler in the constructor.
Finally there is another method to parse the string into the object type such as.
public static class FixedLengthFormatter
{
public static T ParseString<T>(string inputString)
{
Type tType = typeof(T);
var properties = tType.GetProperties(BindingFlags.Instance | BindingFlags.Public); //;.Where(x => x.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false).Count() > 0);
T newT = (T)Activator.CreateInstance(tType);
Dictionary<PropertyInfo, FixedLengthDelimeterAttribute> dictionary = new Dictionary<PropertyInfo, FixedLengthDelimeterAttribute>();
foreach (var property in properties)
{
var atts = property.GetCustomAttributes(typeof(FixedLengthDelimeterAttribute), false);
if (atts.Length == 0)
continue;
dictionary[property] = atts[0] as FixedLengthDelimeterAttribute;
}
foreach (var kvp in dictionary.OrderBy(x => x.Value.OrderNumber))
{
int length = kvp.Value.FixedLength;
if (inputString.Length < length)
throw new Exception("error on attribute order number:" + kvp.Value.OrderNumber + " the string is too short.");
string piece = inputString.Substring(0, length);
inputString = inputString.Substring(length);
kvp.Key.SetValue(newT, piece.Trim(), null);
}
return newT;
}
}
The method above is what does the string parsing. It is a pretty basic utility that reads all the properties that have the FixedLengthDelimeter attribute applied a Dictionary. That dictionary is then enumerated (ordered by OrderNumber) and then calling the SubString() method twice on the input string.
The first substring is to parse the next Token while the second substring resets the inputString to start processing the next token.
Finally as it is parsing the string it is then applying the parsed string to the property of the class Type provided to the method.
Now this can be used simply like this:
string data1 = "Jonh Smith 016Some place in NY, USA 01/01/2014L01";
StudentData student = FixedLengthFormatter.ParseString<StudentData>(data1);
What this does:
Parses a string against property attributes in a fixed length format.
What this does not do:
It does convert the parsed strings to another type. Therefore all the properties must be a string. (this can be easily adapted by adding some type casting logic in).
It is not well tested. This is only tested against a few samples.
It is not by all means the only or best solution out there.
You could use FileHelpers library (NuGet).
Just define the structure of your input file with attributes:
[FixedLengthRecord]
public class StudentData
{
[FieldFixedLength(20)]
[FieldTrim(TrimMode.Right)]
public string name;
[FieldFixedLength(3)]
public string age;
[FieldFixedLength(30)]
[FieldTrim(TrimMode.Right)]
public string address;
[FieldFixedLength(10)]
public string bday;
[FieldFixedLength(3)]
public string level;
}
Then simply read the file using FileHelperEngine<T>:
var engine = new FileHelperEngine<StudentData>();
var students = engine.ReadFile(filename);

C# shortcut notation to create class instance

I'm sure there was a way to easily create an instance of a class but my search of the great interwebs hasn't found it. Lets say I have this:
List<LicencedCustomer> leftList = new List<LicencedCustomer>();
leftList.Add(new LicencedCustomer (LMAA_CODE:"1",LICENSE_NUMBER:"1",TRADING_NAME:"Bobs Liquor",STATE:"NSW",POSTCODE:"2261"));
My class looks like the below.
public class LicencedCustomer
{
public string LMAA_CODE {get; set;}
public string LICENSE_NUMBER {get; set;}
public string TRADING_NAME {get; set;}
public string STATE {get; set;}
public string POSTCODE {get; set;}
public LicencedCustomer(string LMAA_CODE, string LICENSE_NUMBER, string TRADING_NAME, string STATE, string POSTCODE)
{
this.LMAA_CODE = LMAA_CODE;
this.LICENSE_NUMBER = LICENSE_NUMBER;
this.TRADING_NAME = TRADING_NAME;
this.STATE = STATE;
this.POSTCODE = POSTCODE;
}
...
Without the constructor immediately above, I get an error that the class doesn't contain a constructor that takes 5 arguments (initially I tried it with the values only and no field names in the List.Add function).
Is there a shortcut that allows assignment to properties on creation, without needing to define the constructor explicitly?
Thanks!
EDIT: Wide ranging curiosity has resulted from the capitalised properties - they are only that way because they've been built to reflect the headings of an import file. Not my preferred method!
When you use new ( ) you call a constructor that matches the parameters. If you have no defined constructors you will get an implicit parameter less constructor.
To use the shortcut initializer use something like this.
public class sCls
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"};
}
Edit
From comments if you add a consturctor that takes a paramter you lose the implict paramterless constructor
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI"}; // ERROR error CS1729: 'csCA.Program.sCls' does not contain a constructor that takes 0 arguments
}
You can also use any constructor with the initializer list
public class sCls
{
public sCls(string setB)
{
B = setB;
}
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls("hi") {A = 4, B = "HI"};
}
Remember that in all cases the constructor is called before the initializer list even if it has a parameter less constructor. So base class constructions or anything else that happens in the construction of the object will happen first.
public class BSE
{
public BSE()
{
BaseA = "Bob";
}
public string BaseA;
}
public class sCls :BSE
{
public int A;
public string B;
}
static void Main(string[] args)
{
sCls oCls = new sCls() {A = 4, B = "HI" };
Console.WriteLine("{0}", oCls.BaseA);//Prints Bob
}
Add a default constructor, then try something like:
new LicencedCustomer() { LMAA_CODE = ..., LICENSE_NUMBER = ..., ... };
Side note: It's not conventional to capitalize properties.

Categories

Resources