Cannot access a variable due to the access level protection - c#

I have following classes:
class Department
{
private string departmentId;
private string departmentName;
private Hashtable doctors = new Hashtable();//Store doctors for
//each department
public Hashtable Doctor
{
get { return doctors; }
}
}
I have an array list that holds department objects:
private static ArrayList deptList = new ArrayList();
public ArrayList Dept
{
get { return deptList; }
}
I am trying to get all the doctors(the Hashtable in department class) from each department:
foreach (Department department in deptList)
{
foreach (DictionaryEntry docDic in department.Doctor)
{
foreach (Doctor doc in docDic.Value)//this is where I gets an error
{
if (doc.ID.Equals(docID))//find the doctor specified
{
}
}
}
}
But I can not compile the program. It gives an Error:
foreach statement cannot operate on variables of type 'object' because
'object' does not contain a public definition for 'GetEnumerator'

You are trying to iterate through a dictionary entry's Value field treating it as if it was a collection of Doctors. The iteration for docDic should already do what you are looking for, just need to cast the appropriate field (probably Value) of the docDic DictionaryEntry.
Doctor doc = (Doctor) docDic.Value;
Better yet, you could use generics and denote the types of the dictionary key/value at declaration of the map:
private Hashtable<string, Doctor> doctors = new Hashtable<string, Doctor>();
(similar change for the Doctor field)
Then you don't need the casting above at all.
Note: I assumed you are mapping from a doctor's id (key) to the Doctor objects (value), and that the id is a string

Prefix your class with a Public access modifier
public class Department
{
private string departmentId;
private string departmentName;
private Hashtable doctors = new Hashtable();//Store doctors for
//each department
public Hashtable Doctor
{
get { return doctors; }
}
}

Related

Convert List<string> to Model class

Having issue with converting List to Student object in c#.
I have a C# model class as below:
public class Student{
public int ID{get;set;}
public string StudentName{get; set;}
public string StudentAddress{get; set;}
public string StudentRemarks{get; set;}
public string AdditionalInfo{get;set;}
}
I have another class where I have a List which holds data as below (Since this is just a list of string, it won't have any property names in front of it such as 'ID: 001') Note: This string will not have any data for 'AdditionalInfo'.
001
John, Snow
NewYork
Sample test info
Now I have another class where I wanted to convert this List to my 'Student' class where 001 has to be assigned to ID, John Snow has to be assigned to 'StudentName', NewYork has to be assigned to 'StudentAddress', Sample test info has to be assigned to 'StudentRemarks'. Since this doesn't have any data provided for 'AdditionalInfo' property, this should be assigned with empty or null value in it. Here is the class
public class StudentInfoService
{
public List<string> GetStudentInfo(string data)
{
var studentData = new List<string>();
foreach (var line in File.ReadLines(data))
{
if (!string.IsNullOrWhiteSpace(line))
{
var data = line.Split('|');
foreach (var item in data)
{
studentData.Add(item);
}
studentData.ConvertAll(c => (Student)c); //Here is where I am struggling to convert the list string to model class
}
}
return studentData ;
}
}
The issue is, I want to convert the list to 'Student' object and automatically assign all the data to the respective properties by order(there won't be any null or empty data in between other than the 'AdditionalInfo'). Student object will have only one student record. It won't have a list of records. So I need to convert the List to Student object. Please help me with this.
You will need to write code to map lines of text to a model instance, e.g.
public Student GetStudent(List<string> list)
{
return new Student
{
ID = int.Parse(list[0]),
StudentName = list[1],
StudentAddress = list[2],
StudentRemarks = list[3],
AdditionalInfo = (list.Count > 4) ? list[4] : null
};
}

MongoDB structure uses field which can be a class with values or just string

I have mongoDb collection with following structures in which the Other field can be a anonymous type class with few properties or just a string in some cases.
{
"_id": "ObjectId('test1')",
"PersonToken": "testToken1",
"Other": "string"
}
{
"_id": "ObjectId('test2')",
"PersonToken": "testToken2",
"Other": {
"Person" : "John",
"Case" : "777"
}
}
I need to read all collection records and change the fields PersonToken and Person if the collection record has them.
In my project I created a model to work with values and I have problem with type of Other property.
If I define it like a class with properties the error appears when the db record value of Other is string.
If I define it like a string the error appears when the db record value of Other is class.
Here is my model code :
[BsonIgnoreExtraElements]
public class MyModel
{
[BsonRepresentation(BsonType.ObjectId)]
public string Id;
public string PersonToken;
public Other Other;
}
[BsonIgnoreExtraElements]
public class Other
{
public string Person,
public string Case
}
And my try to read all db records
public void MyClass
{
private readonly IRepository _myRepository;
public MyClass()
{
_myRepository = new MongoDbRepository(LoadRepositoryConfig("MyCollection"));
}
public async void ReadAllDbValues()
{
var allDbValues = _myRepository.GetCollection<MyModel>("MyCollection")
.Find(new BsonDocument()).ToList();
foreach (var dbValue in allDbValues)
{
if (!string.IsNullOrEmpty(dbValue.PersonToken))
{
dbValue.PersonToken = updatedPersonToken;
}
if (!string.IsNullOrEmpty(dbValue.Other?.Person))
{
dbValue.Other.Person = updatedOtherPerson;
}
await _myRepository.GetCollection<MyModel>("MyCollection").UpdateOneAsync(
Builders<MyModel>.Filter.Where(x => x.Id == dbValue.Id),
Builders<MyModel>.Update
.Set(x =>x.PersonToken,dbValue.PersonToken)
.Set(x=>x.Other.Person,dbValue.Other.Person));
}
}
}
There is some possibility to read all values from db collection ?
I tried to make Other field of type object, but then I can't access the fields under the Other class to work with them properly.
I tried to make the variable allDbValues to get collection not from MyClass, but of type dynamic, but then db updating operation gets error that 'An Expression tree may not contain a dynamic operation'

NHibernate one-to-many removing related records

I have three tables with the following structure:
Todo
Id
Name
User
Id
Name
TodoUser
Id
TodoId
UserId
Status
For Todo.ResponsibleUsers I have created the following mapping:
private IList<TodoUser> responsibleUsers = new List<TodoUser>();
[Bag(0, Name = "ResponsibleUsers", Cascade = CascadeStyle.AllDeleteOrphan, Table = "TodoUser", Inverse = true)]
[Key(1, Column = "TodoId")]
[OntToMany(2, ClassType = typeof(TodoUser))]
public virtual IList<TodoUser> ResponsibleUsers {
get { return responsibleUser; }
set { responsibleUsers = (IList<TodoUser>)value; }
}
Does the property ResponsibleUsers have to be of type IList<TodoUser> or can it also be of type List<TodoUser>?
I would like to do something like todo.ResponsibleUsers.RemoveAll(itemsToRemove); which is not possible on an IList<TodoUser>
To answer the question:
Does the property ResponsibleUsers have to be of type IList<TodoUser> or can it also be of type List<TodoUser>?
Check the doc:
Chapter 6. Collection Mapping
6.1. Persistent Collections
NHibernate requires that persistent collection-valued fields be
declared as a generic interface type, for example:
public class Product
{
private string serialNumber;
private ISet<Part> parts = new HashSet<Part>();
public ISet<Part> Parts
{
get { return parts; }
set { parts = value; }
}
public string SerialNumber
{
get { return serialNumber; }
set { serialNumber = value; }
}
}
The actual interface might be
System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IList<T>,
System.Collections.Generic.IDictionary<K, V>,
System.Collections.Generic.ISet<T>
So, yes, we must use interface.
To solve the issue with
I would like to do something like todo.ResponsibleUsers.RemoveAll(itemsToRemove);
We can implement some custom extension method as
public static class Ext
{
public static void RemoveAll(this IList<T> list, IEnumerable<T> toRemove)
{
... // remove items matching toRemove from the list
}

C# Match User Inputs to Array

I'm writing some code where I have some information about customers stored in an array called members (id, initials). I then ask the user for their id and initials and match the inputs to the stored information from array members. If they match I move on. However I get an error in my coding: "an object reference is required to access non-static field method or property". The error comes from the if statements. Any suggestions on how to correct this issue?
Some background info: I have two classes, one called Customer and one called Menu. The Menu is the main class while Customer is the class I reference from.
This is from my Menu class:
int L = 0;
string I = "";
Customer[] members = new Customer[2];
members[0] = new Customer(3242, "JS");
members[1] = new Customer(7654, "BJ");
Console.Write("\nWhat is your Loyalty ID #: ");
L =Convert.ToInt32(Console.ReadLine());
Console.Write("\nWhat is your first and last name initials: ");
I = Console.ReadLine();
if (L==Customer.GetId())
{
if (I == Customer.GetInitials())
{
Console.WriteLine("It matches");
}
}
else
{
Console.WriteLine("NO match");
}
Console.ReadKey();
}
}
}
This from my Customer class
private int id;
private string initials;
public Customer ()
{
}
public Customer(int id, string initials)
{
SetId(id);
SetInitials(initials);
}
public int GetId()
{
return id;
}
public void SetId(int newId)
{
id = newId;
}
public string GetInitials()
{
return initials;
}
public void SetInitials(string newInitials)
{
initials = newInitials;
}
The error means exactly what it says. You can't access the GetId() function of Customer by calling Customer.GetId() because GetId() only works on an instance of Customer, not directly through the Customer class.
Customer.GetId(); //this doesn't work
Customer myCustomer=new Customer(); myCustomer.GetId(); //this works
To check the user's input against your array of inputs, you need to iterate through the array (or alternatively, use Linq).
I'm going to use a generic list, because there's not really a good reason to use arrays in most cases.
List<Customer> customers=new List<Customer>();
Customers.Add();//call this to add to the customers list.
foreach(var c in customers)
{
if(c.GetId() == inputId)
{
//match!
}
else
{
//not a match
}
}
You can also improve your Customer class by using properties, or auto properties (which doesn't need a backing field). Here's an auto property example:
public string Id {get; set;} // notice there's no backing field?
Using the above auto property syntax would allow you do to this:
var customer = new Customer();
string id = customer.Id; // notice there's no parentheses?
Properties and auto properties allow for a cleaner syntax than having to write Java-style separate getters/setters.

List custom class members and type

This seems like the most basic thing ever but somehow I couldnt find the answer and couldnt figure it out.
Lets say I have a custom class:
public class WineCellar
{
public string year;
public string wine;
public double nrbottles;
}
Now I would like a function:
WineCellar ex = new WineCellar();
ex.members();
This should return: year, wine, nrbootles.
And:
ex.members().types();
Should return: string, string, double
I guess on the same note, lets say you have one instance {2010, Rioja, 6}. Is there syntax that returns these by indexing? i.e.
ex[1]
or
ex.{1}
that returns 2010?
Sorry for the basic question.
As Michelle said in the comments, this sounds like a wrong approach to a bigger problem.
However, if you do need this kind of things, you can get the using reflection:
//returns a list of propertyInfo objects for the class
// with all kinds of usefull information
public List<PropertyInfo> GetMemberInfos()
{
return this.GetType().GetProperties().ToList();
}
//returns a list of property names
public List<string> GetMemberNames
{
return this.GetType().GetProperties().Select(pi => pi.Name).ToList();
}
//returns a list of names of the property types
public List<string> GetMemberTypeNames
{
return this.GetType().GetProperties().Select(pi => pi.PropertyType.Name).ToList();
}
//indexer that uses the property name to get the value
//since you are mixing types, you can't get more specific than object
public object this[string property]
{
get { return this.GetType().GetProperty(property).GetValue(this); }
set { this.GetType().GetProperty(property).SetValue(this, value); }
}
//indexer that uses the property index in the properties array to get the value
public object this[int index]
{
get { return this.GetType().GetProperties()[index].GetValue(this); }
set { this.GetType().GetProperties()[index].SetValue(this, value); }
}
Note that all of these methods are very slow, because in general, reflection is slow. You can try to cache some thing to speed it up.
Also, the last method is downright dangerous. It will (try to) read and write to an array that does not have a guaranteed order. In fact, the documentation specifies:
The GetProperties method does not return properties in a particular
order, such as alphabetical or declaration order. Your code must not
depend on the order in which properties are returned, because that
order varies.
For example, if you change your class to:
public class WineCellar
{
public string year;
public string region;
public string wine;
public double nrbottles;
}
and you were used to using winecellar[1] = "Pinot Noir" that will most likely now update the region property, instead of the wine property.
This is how you would implement Members method (In case if you wanted property names as strings)
public List<string> Members()
{
List<string> propNames = new List<string>();
foreach (var prop in typeof(WineCellar).GetProperties())
{
propNames.Add(prop.Name);
}
return propNames;
}
And this is how you would implement Types (In same case)
public List<string> Types()
{
List<string> propTypes = new List<string>();
foreach (var prop in typeof(WineCellar).GetProperties())
{
propTypes.Add(prop.PropertyType.ToString());
}
return propTypes ;
}
And the last thing if you want to get values of the parameters like this ex[n] you can just make a simple indexer in you class like this
public string this[int n]
{
get
{
int current = 0;
foreach (var prop in typeof(WineCellar).GetProperties())
{
if (current == n)
return prop.GetValue(this, null).ToString();
current++;
}
return null;
}
}
but for these methods to work you should change your variables into properties like this
public class WineCellar
{
public string Year { get; set; }
public string Wine { get; set; }
public double Nrbottles { get; set; }
}
You can use reflection
foreach (var prop in typeof(WineCellar).GetProperties())
{
if (prop.PropertyType == typeof(double) || prop.PropertyType == typeof(double?))
{
}
}
to get the value, you can do:
prop.GetValue(obj);

Categories