I have a class (students) with say 2 strings and an int array
A second class then does this:
List<student> myS = new List<student>();
All of this works correctly and I have a list containing multiple students. I am however having difficulty accessing the values within the int[].
So, my student list is populated from a database and into a list.
I then have a generic class which has a parameter List which I then want as a data table. The generic class will be called for the student class, subjects class and other classes - some of which may contain arrays and some which do not.
If I debug and step through, I get the following:
(() myS.stu[6].termMark[1] and the value is 50. However if I enter int d =stu[6].termMark[1] the error is T does not contain a definition for termMark and no extension method 'termMark' accepting a first argument of type T could be found.
int d = myS[0][1] returns the error
cannot apply indexing with [] to an expression of type 'T'
. I have tried various things like creating a separate list and adding it to myS. Nothing works.
Thanks in advance for the help.
I am fairly new to this and probably missing the obvious...
You must read about Generic Constraints
You cannot do much with an argument of type T.
If your function accepts arguments of type student , add a constraint like this
private static void NewMethod<T>(List<T> myS) where T : student
{
int d = myS[0].IntArray[1];
}
The following is not related your problem...
If you add an indexer to your class you can make it a little shorter
public class student
{
public int[] IntArray;
public int this[int x]
{
get
{
return IntArray[x];
}
}
}
private static void NewMethod<T>(List<T> myS) where T : student
{
int d = myS[0][3];
}
Perhaps the type T does not hold any definition for indexers. But, your field (int[]) does. So, instead of calling the indexer upon your object (student) call it on the field of it. So, for this answer I would assume that your object is declared as class like this
public class student {
public string S { get; set; }
public string s { get; set; }
public int[] integers { get; set; }
}
Now, you can indeed call the indexers on the integers field but not on the student object itself (it does not have any indexing mechanism). Such as,
int d = myS[0].integers[1]; // <-- your code should be
The above code (if compiled) would give you the element at the index 1 (2nd element) of the first object in the list. You were instead calling the element at index 1 of the student (which does not have indexers?).
Related
I have 2 classes which are inherited in this manner
public class PartsParent
{
}
public class PartsCar : PartsParent
{
public int WheelRadius { get; set; }
public int Price { get; set; }
}
public class PartsBike : PartsParent
{
public int Length { get; set; }
public int Weight { get; set; }
public int Price { get; set; }
}
And i have a function that accepts the class PartsParent as parameter and how can i convert this as partsCar / as PartsBike inside the function and access properties like Price WheelRadius etc?
private int PriceCollection(PartsParent mainObject)
{
int _price=0;
mainObject.OfType(PartsCar).Price;// something similar??
return _price;
}
Well, you are trying to cast a parent type to a child type, that is not really possible, why ?
The answer is that the parent P you are trying to cast to child C1 can be actually and originally of type C2, so the cast would be invalid.
The best way to explain this is a phrase that I read somewhere here on stackoverflow
You can't cast a mammal into a dog - it might be a cat.
You can't cast a food into a sandwich - it might be a cheeseburger.
What you can do though to turn around this situation is something like this :
(mainObject is PartsCar) ? (PartsCar)mainObject : mainObject
Which is equivalent to :
mainObject as PartsCar
Then access mainObject's cast result using the null coalescing operator (because if as fails, the cast result will be null instead of throwing an Exception).
The generic method OfType<T> that you tried to use is an extension method that can be used with objects of type IEnumerable<T'> , which I guess is not your case.
The idea of inheritance is to group up what is common in a super class, and leave other specific details to sub-classes. So if a property, say Price, is excepted from all sub-classes, then it should be declared in the super class.
However, if you still want to use it this way, then what are you looking for is:
int _price = ((PartsCar)mainObject).Price;
However, what if the object was of some other class, say PartsGift that inherits from PartsParent, but does not have a price? Then it will crash.
You almost really need to check your design.
BTW, if you want to check if an object is really of a specific class, then you can use is.
int number = 1;
object numberObject = number;
bool isValid = numberObject is int; // true
isValid = numberObject is string; // false
You can use is keyword to check the type and as keyword to convert to the target child type as following.
if (mainObject is PartsCar)
{
var partscar = mainObject as PartsCar;
// Do logic related to car parts
}
else if (mainObject is PartsBike)
{
var partsbike = mainObject as PartsBike;
// Do logic related to bike parts.
}
It's possible if you separate uncommon properties your code into block:
if (mainObject is PartsCar)
{
//Seprated code for PartsCar
// WheelRadius...
//Price...
}
else if (mainObject.GetType() == typeof(PartsBike))
{
//Seprated code for PartsBike
//Length
//Weight
//Price
}
The following seems to be a class array?
Chemical.ChemicalName[IndexNumber]
It seems that there are several other fields associated with Chemical, such as Cost, Quantity, SupplierName (Chemical.Cost etc).
I was wondering what this type of variable is called? A class array? I've been searching online about arrays and can't seem to find any documentation on this.
And secondly, how do I declare such a variable?
Assuming it's a property, not an array , so you cannot access using an index,
public class Chemical
{
// Field
public string ChemicalName;
...etc
}
if chemical is an array , then you can declare like this,
Chemical[] Chemicals = new Chemical[200];
Then you can access the particular element using the index,
Chemicals[IndexNumber].ChemicalName
EDIT
If you want to have ChemicalName as a array inside the class,
public class Chemical{
public ChemicalName[] ChemicalNames = new ChemicalName[5];
]
you can access like this,
Chemical[] Chemicals = new Chemical[200];
c[index].ChemicalNames[index];
Variable would look something like that
public class Chemical{
public ChemicalName[] ChemicalNames = new ChemicalName[5];
...
}
So you can invoke it like that
Chemical c = new Chemical();
c.ChemicalNames[index];
OR, you can also declare the Array as static so you wont need an intance of the class to get the array e.g.
public class Chemical{
public static ChemicalName[] ChemicalNames = new ChemicalName[5];
...
}
to call a static, simply use class.variable/method name
Chemical.ChemicalNames[index];
It is a class property that implements an indexer. Usually this is an array, but it can be something else as long as it implements this[int index].
You can declare one by declaring it as a class property. For example,
class Book
{
public Book(int numPages)
{
Pages = new Page[numPages];
}
public Page[] Pages {get;}
}
You can then instantiate an instance and access a page.
Book myBook = new Book(100);
myBook.Pages[50]=new Page("Hi, welcome to Page 50");
Console.Write(myBook.Pages[50].GetText());
Let me consider this statement from the question Chemical.ChemicalName[IndexNumber], We can consider Chemical as a class or as an object of some other class. If it is a class means the ChemicalName will be a static.
Then comes the ChemicalName definitely it will be a collection(List/Array or something like that) or even an object of a class which having an indexer.
Case 1: consider Chemical is class and ChemicalName is a List of string So the Definition will be :
public class Chemical
{
public static List<string> ChemicalNames = new List<string>(){"name1","name 2"};
}
So that you can access a single name like the following:
string someChemicalName=Chemical.ChemicalNames[0]; // will be name1
Case 2: consider Chemical is an object of a class and ChemicalName is a List of string So the Definition will be :
public class Chemicals
{
public List<string> ChemicalNames;
}
Then you can access create the Chemical by using the following code:
Chemicals Chemical= new Chemicals();
Chemical.ChemicalNames=new List<string>(){"name1","name 2"};
Here also you can workout your statement like this
string someChemicalName=Chemical.ChemicalNames[0]; // will be name1
Let's parse Chemical.ChemicalName[IndexNumber]:
IndexNumber is probably some value of one of integer types - let guess int IndexNumber. Other options could be enum or any type as you can use indexer with any arguments.
[IndexNumber] is indexing something. Since there is no
Static Indexers? in C# it means ChemicalName can't be class name of static class like following
namespace Chemical {
static class ChemicalName{}
}
so it means that ChemicalName is either property or field of Chemical.
Now for Chemical there are more options
it could be static class with ChemicalName as static property:
static class Chemical{
public static string[] ChemicalName = new[] {"Food", "Poison"};
}
it could be local variable of some type that has ChemicalName as instance property:
class ChemicalType{
public string[] ChemicalName = new[] {"Food", "Poison"};
}
...
void MyMethod()
{
// implicitly typed, same as `ChemicalType Chemical`
var Chemical = new ChemicalType();
int IndexNumber = 1;
Console.WriteLine(Chemical.ChemicalName[IndexNumber]);
}
it could be field or property of your class (with any accessibility as to get Checmical.ChemicalName syntax to work for property it need to be used inside a method of your class)
class MyClass
{
// one of any combination:
// private field
ChemicalType Chemical = new ChemicalType();
// or protected automatic property
protected ChemicalType Chemical {get;set;}
// or public property
ChemicalType _chemical;
public ChemicalType Chemical {get {return _chemical;}}
...
}
Finally let's see what ChemicalName could be: the only requirement is to allow indexer by some type. including int. This gives very broad set of types as many of built in types support indexing.
array is most common one string[] ChemicalName
just string - somewhat strange given name of variable, but possible - string ChemicalName. When indexing will give single char result
List<string>
dictionary, this option allows broader range of indexing - i.e. by strings Dictionary<string,string> ChemicalName.
custom type implementing similar to public string this[int i] (or any other return type).
I have a List of Items. Item is an object with multiple constructors, thus an item can be created in several forms.
Example of class Item with two constructors.
public class Item
{
public string name = "";
public int age= 0;
public int anotherNumber = 0;
public Item(string iName, int iAge)
{
name = iName;
age= iAge;
}
public Item(string iName, int iAge, int iAnotherNumber)
{
name = iName;
age= iAge;
}
}
I have then a Json file in the form of:-
[{"name":"Joseph","age":25},{"name":"Peter","age":50}]
I'm using the below method to read file and populate list using Newtonsoft.Json API.
public List<Item> ReadJsonString()
{
List<Item> data = new List<Item>();
string json = File.ReadAllText("\\path");
data = JsonConvert.DeserializeObject<List<Item>>(json);
return data;
}
If I have only one constuctor in the Item class (example the constructor that takes 2 arguments) this method works fine and I am able to populate the list. However when I add the second constructor in class Items(since I want to be able also to read Json files with the third attribute..
Example:-
[{"name":"Joseph","age":25, "anotherNumber": 12},{"name":"Peter","age":50, "anotherNumber": 12}]
The ReadJsonObj method fails with error "Unable to find a constructor to use for type Item". I can fix this issue by creating multiple class Item (e.g. ItemA, ItemB),one that takes three variables and the other that takes two variables. However I would like to have only one Item class.
I cannot find out why this is happening and how to fix such an issue.
You can use properties instead of regular fields and constructor initialization.
public class Item
{
public string name {get;set;}
public int age {get;set;}
public int anotherNumber {get;set;}
}
Thus you will cover both deserialization cases.
how to assign value for an array variable when it is declared in different class? Below is the sample codes for easier understanding of my problem:-
// Below is a class customer that has three parameters:
// One string parameter and Two int array parameter
public class Customer
{
public string invoiceFormat { get; set; }
public int [] invoiceNumber { get; set; }
public int [] customerPointer { get; set; }
public Customer(
string invoiceFormat,
int[] invoiceNumber,
int[] customerPointer)
{
this.invoiceFormat = invoiceFormat;
this.invoiceNumber = invoiceNumber;
this.customerPointer = customerPointer;
}
}
// How to assign value for invoiceNumber or customerPointer array in
// different windows form?
// The following codes is executed in windowsform 1
public static int iValue=0;
public static Customer []c = new Customer [9999];
c[iValue] = new Customer(textBox16.Text, invoiceNumber[0].iValue + 1,
customerPointer[0].iValue);
// I have an error that the name 'invoiceNumber and customerPointer'
// does not exist inthe current context
what you have
c[iValue] = new Customer(textBox16.Text, invoiceNumber[0].iValue + 1, customerPointer[0].iValue);
which is completely wrong and is why you get the error : the name 'invoiceNumber and customerPointer' does not exist inthe current context
you never declare any array for invoiceNumber or CustomerPointers. Both of these are members of your class which is where I think you are getting confused. I am not even going to take a guess at what invoiceNumber[0].iValue +1 is to be as an int has no members, its a data type
so to fix this we would do something such as
//create some arrays
int[] invoicesNums = new int[]{1,2,3,4,5};
int[] customerPtrs = new int[]{1,2,3,4,5};
//create a new customer
Customer customer = new Customer("some invoice format", invoicesNums, customerPtrs);
//add the customer to the first element in the static array
Form1.c[0] = customer;
ok so thats how you should do that however, I really think you need to stop and take a deeper look into classes, arrays, data types and OOP as this will save you from a major headache when you get further down the road with your Program.
You are attempting to use a value that does not exist yet. Look at your constructor:
public Customer(string invoiceFormat, int[] invoiceNumber, int[] customerPointer)
{
this.invoiceFormat = invoiceFormat;
this.invoiceNumber = invoiceNumber;
this.customerPointer = customerPointer;
}
This means you need to pass a string, a FULL array of int and another COMPLETE array of int. By attempting to do this:
c[iValue] = new Customer(textBox16.Text, invoiceNumber[0].iValue + 1, customerPointer[0].iValue);
You are calling upon variables that don't exist yet. Think about the word constructor. That creates the object and initializes the internal variables. invoiceNumber[] and customerPointer[] are never assigned by passing another array parameter. This is why you are receiving that error message. If you used your constructor to initialize those arrays and then pass a single invoiceNumber and single customerPointer, which are then added to the initialized array then this would work. However, it sounds like your internal values should not be arrays, then you'd be able to just pass a single int value for each of those parameters.
How do I instantiate an array property using Reflection based on the code below?
public class Foo
{
public Foo()
{
foreach(var property in GetType().GetProperties())
{
if (property.PropertyType.IsArray)
{
// the line below creates a 2D array of type Bar. How to fix?
var array = Array.CreateInstance(property.PropertyType, 0);
property.SetValue(this, array, null);
}
}
}
public Bar[] Bars {get;set;}
}
public class Bar
{
public string Name {get;set;}
}
The first parameter of Array.CreateInstance expects the element type of the array. You pass the entire property type, which is, as you have just found out by checking property.PropertyType.IsArray, an array type (specifically, Bar[] - i.e. an array of Bar elements).
To get the element type of an array type, use its GetElementType method:
var array = Array.CreateInstance(property.PropertyType.GetElementType(), 0);
I suppose you will replace the zero passed to the second argument with a higher number when required, unless you actually want only empty arrays.