Ok here is my dilemma, I want to create an array of custom objects but then be able to do something like list[index].method call.
as an example:
program starts
program creates a master array which holds GenericClass< T >(param)
each generic class then creates an array of type T
I can get that part to work ok but then when I try to use my object methods such as
object[] MasterList = new object[MASTER_LIST_SIZE];
// add contents to MasterList
MasterList[index].setValueAt(MethodIndex, value);
I get a message that reads object has no method named setValueAt which requires one parameter(s)
I will admit that what I am trying to do is rather dumb and I could probably do it easier with reading a text file or something but if there is a way to do it like this I would like to know how or at least what I am missing.
There are a lot of unknowns about what you are doing but my best guess is that you need to cast the result to the type you need.
((GenericClass<T>)MasterList[index]).setValueAt(MethodIndex, value);
Related
For this code snippet below, which probably won't need an explanation to the persons who can answer my question:
protected readonly List<TEntity> Records; //Within the class declared.
protected virtual void ReadFile()
{
//So the file exists, is not null and not whitespace only
var serializer = new XmlSerializer(Records.GetType());
using (var reader = new StringReader(contents))
{
var records = (List<TEntity>)serializer.Deserialize(reader);
Records.Clear();
Records.AddRange(records);
}
}
It's about the line:
var records = (List<TEntity>)serializer.Deserialize(reader);
(1) How could I've known (deduced) that this cast was possible? I looked up that the Deserialize() methods returns the type "object". So that's can't be the hint. (Edit: I mean during coding/design time. Not compiling afterwards for trial and error. So think goal-wise: goal = store xml data into a list<>. Is it possible through a simple cast (yes) and how could I have known in advance?).
(2) How could I've / can I deduce(d) how variable "records" would end up? For example, what shouldn't make me think that only a single entry is written to the list and that single index holds all of the XML content? (as opposed to keeping a nice structure whilst writing it to the list)
The final goal of my question is to understand when such a cast is needed and especially how the actual cast makes sense. I'm wiling to put in effort in it with practice and experimentations. But I don't know how to think.
a) I"m a beginner, though learning fast i.m.o.
b) I Have read and understood implicit/explicit casting and understood that it's based on range, as opposed to data size. But those tutorials restrict to built in basic types like int, float, decimal (you name it). Now this problem domain (casting) I would like to move to a higher level.
The cast
var records = (List<TEntity>)serializer.Deserialize(reader);
works because of
new XmlSerializer(Records.GetType());
The cast from object to anything will always compile but yield a runtime exception when the types don't match.
The serializer knows about the root type from its constructor and will create a result of that type. If the XML doesn't match that, it will throw an error. You cannot deserialze a single TEntity with this, only a List<> with 0 or more elements.
You can verify it easily:
object temp = serializer.Deserialize(reader);
// print or inspect temp.GetType() here
var records = (List<TEntity>)temp;
Note that if XmlSerialzier had been designed as a generic type then the cast would not have been necessary:
var serializer = new XmlSerializerGeneric<List<TEntity>>();
var records = serializer.Deserialize(reader);
But it wasn't, it uses the older way of 'dynamic typing' through the System.Object class.
It would be much obvious if instead of this
var serializer = new XmlSerializer(Records.GetType());
you used this
var serializer = new XmlSerializer(typeof(List<TEntity>));
The rule is simple. What ever type you pass to the XmlSerializer constructor, you can safely cast the Deserialize result to that type.
The cast is needed because XmlSerializer (as well as Enum and many other framework classes) exists from a long time before the generics were added, so returning an object is the only choice it had. And it must remain this way because of backward compatibility (to not break the existing code you have written).
How could I've known (deduced) that this cast was possible?
One way is to use the debugger. Put a breakpoint on the Records.Clear(); line just after records is set. Then in either the Watch window or the Locals window, take a look at the type of the records variable. It might say something like this:
object { List<TEntity> }
records is a List<TEntity> but it's being passed as an object because the call to serializer.Deserialize(reader) returns an object. And if you didn't declare an implicit conversion from object to List<TEntity>, you have to use an explicit conversion.
I recommend against implicit conversions for all but the most obvious cases.
(1) How could I've known (deduced) that this cast was possible?
It all began here,
protected readonly List<TEntity> Records;
You don't have to deduce but you already know you are reading file contents from a file which has some XML with some sort of structure and since you are using a list you know upfront that there are going to be mulitple list items
I looked up that the Deserialize() methods returns the type
"object". So that's can't be the hint.
object class is not used directly (So basically that is a hint that you have to cast) and it must be casted to some type (in this case List<TEntity>) before it could be used.
(2) How could I've / can I deduce(d) how variable "records" would end
up?
Lets say I want to create list of persons, I would know I would keep some structure for example,
I have following XML
<persons>
<person>
<name>Chuck Norris</name>
<age>137</age>
</person>
<person>
<name>Donald Trump</name>
<age>19</age>
</person>
<persons>
You know you want to get the records of person your list would be declare like this, List<Person>. You know Deserialize() method returns object and you would want to read persons data, you would cast that object into List<Person>. So basically what I am trying to say is that both the question you asked are based on the assumption and choices made at the design time of you application.
I'm new to C#, so this problem may be trivial to many of you...
I'm writing simple application that uses API of a certain website. I'm using and altering an example from this website.
So the problem is when I'm instantiating an object that (in simple words) returns simple variable like string, int or even user-defined type everything seems to be working fine, but when I try to instantiate an element that is an element array of user-defined:
request.#parameters.examplename = new somenamespace.SomeName.UserType();
type I get a message like this:
"Cannot implicitly convert type "somenamespace.SomeName.UserType' to 'somenamespace.SomeName.UserType[]'."
Can you explain to me what am I doing wrong? Is there a different way to instantiate an element array? If you need more information please let me know.
You should change your line to:
request.#parameters.examplename =
new somenamespace.SomeName.UserType[] { new somenamespace.SomeName.UserType() };
You are currently trying to assign a single UserType value to something that wants an array of UserType's. So this is solved by creating an array (the new[] part) and populating it with the UserType value (the {} part).
Given your error output it looks like your syntax is incorrect. You have a UserType array (UserType[]) called request.#parameters.examplename which you are attempting to assign a UserType object to; new UserType() calls the constructor on the object.
What you require is a newly instantiated array of UserTypes:
request.#parameters.examplename = new somenamespace.SomeName.UserType[];
I have a C# class that does some parsing of XML passed in to its one public method. The idea is that the method pulls info out of the XML, creates objects and sets up collections of them in public properties...
public class XmlParser {
public List<Customer> Customers { get; set; }
public void ProcessXml(string xml) {
XElement data = XElement.Parse(xml);
CreateEntities(Customers, data);
// do other stuff...
}
}
This way, we can do things like this in the calling code...
XmlParser xp = new XmlParser();
xp.ProcessXml(xml);
// do something with xp.Customers
I am trying to write a private generic method in the parser class, which would be used by the ProcessXml() method, and save me writing boilerplate code over and over again. The beginning of this method looks like this (other parameters missed out for clarity)...
private void CreateEntities<T>(List<T> collection, XElement data) {
if (collection == null) {
collection = new List<T>();
}
// process the XElement passed in, and add objects to the collection
}
I'm trying to use it like this...
CreateEntities(Customers, data);
...where the other parameters allow the compiler to know the generic type, and allow the method to know which entities to create etc.
However, the problem I have is that whilst the method itself works fine, and the collection variable is populated correctly, the public Customers property remains null.
I thought that passing a reference type, such as a List<> to a method allowed the method to modify the type, and have those changes seen outside the method, like in the answer from recursive in this SO post (I know that's a Dictionary, but I would have thought the principle would be the same).
Howcome my method can set collection to a new List<>, but Customers (which is the same object) remains null?
Update: Sigh, I ought to learn to read error messages!
Before I posted my question, I had tried passing the collection by ref, and it gave me compiler errors. I obviously didn't pay enough attention to the messages before moving on to plan B.
Having read the replies here, I tried ref again, and spotted that the compiler error was because I was trying to pass a public property by ref, which is not allowed. I changed the property from an automatic one to one with a backing field, passed the backing field by ref and it all works fine!
I thought that passing a reference type, such as a List<> to a method allowed the method to modify the type, and have those changes seen outside the method
You're getting confused with passing a parameter by reference (using the ref modifier), and passing a reference by value.
When you pass the value of a reference type (e.g. List<Customer>) to a method, you're still passing that argument by value by default. You can change the contents of the object that the variable's value refers to, but you can't change which object the original argument referred to, which is what you're trying to do.
Think about it like this... if I hand someone a piece of paper with my home address on, then they can do two things:
They can go to my house and paint my front door red
They can cross out my address and write a different address on the piece of paper
I will be able to see the result of the first action - it's changing something about the house itself. I won't be able to see the result of the second action, because it's just changing what's on the piece of paper... which is just a copy of what I know to be my home address.
For more details, refer to my article on parameter passing in C#.
To fix your problem, I would just change your CreateEntities method to return a list, rather than accepting one:
private List<T> CreateEntities<T>(XElement data)
{
var list = new List<T>();
// Populate the list...
return list;
}
If the caller wants to add those to an existing list, they can do so easily.
I think you missing the passing reference type by using ref. For more information ref (C# Reference)
I have a enum type (i.e. View). I would like to extract a part of this enum [Top,Bottom,Left,Right,Front,Rear] to add in to a combo box as ComboBox.DataSource = Enum.GetValues(typeof(View_extracted)).
Is it possible?
enum View {Top,Bottom,Left,Right,Front,Rear,Trimetric,Isometric,Diametric}
View_extracted should contain first 6 values only:
{Top,Bottom,Left,Right,Front,Rear}
LINQ to the rescue!
Enum.GetValues(typeof(View)).Cast<View>().Take(6);
If you wanted it to be a proper enum, you can mess around with ILGen but it's way, way more trouble than it's worth.
No, it's strictly not possible to create a type View_extracted, that would be able to be called using that exact code to create the stated results.
While you could create another enum that had values that happened to have the same names as this other enum, and you could create a method (that would have to be different than what you described) to get at a list of this enum's values, it's a very brittle system.
What I would suggest doing, instead of creating a new enum as a view, is to simply create a new method as a view that returns the values of this enum, something like:
public static IEnumerable<View> ExtractedView()
{
//return a sequence of the views here, whether it be a hard code list,
// or a filtered result of a call to Enum.GetValues, or whatever
}
I need to copy one element of a generic collection and add it to the list. Something similar to this:
private List<CalculationResult> cantileverResults = new List<CalculationResult>();
cantileverResults.Add(cantileverResults[previousIndex]);
The problem with this solution is that when I modify the new element, the previousIndex element changes as well. I believe this is because they are reference-type, not value-type. How can I just copy (clone?) the information from one element to another without affecting each other any further?
You will need to create a new object when adding it.
This can be done in several ways - a helper method that takes an object of your type (CalculationResult) and returns a completely new one.
Perhaps have a constructor overload that does this.
There are many ways to achieve such a thing - implementing ICloneable and having the Clone method return a new object.
For example, if you were to create a constructor overload, this is how you could use it:
cantileverResults.Add(new CalculationResult(cantileverResults[previousIndex]));