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[];
Related
Imagine following "path" :
MyObject.MyFirstList[0].MySecondList[0].MyProperty = "Hello"
MyProperty is of type String.
None of the types is known at compiletime, only runtime via reflection of assembly.
I have everything, but i can not set the second list on the first with SetValue. I always get either null-ref exceptions or "target type does not match".
What I have tried so far:
iteration 1:
var constructedList = Activator.CreateInstance(constructedListType);
target.GetType().GetProperty(propertyToAdd).SetValue(target, constructedList)
Iteration 2:
Same way, works as well. So now we have MyObject.MyFirstList[0].MySecondList[]
Iteration 3: TODO: Create instance of first object of MySecondList and set its MyProperty-property to the created property:
var target = Activator.CreateInstance(typeOfItem);
target.GetType().GetProperty(propertyToAdd)?.SetValue(target, null);
So to summarize the question:
This works:
someInstance.GetType().GetProperty(someProperty).SetValue(someInstance, objToSet);
Why does something like this not work? Or does it - if yes, how?
someInstance.GetType().GetProperty(someList.listInsideSomeList.finalProperty).SetValue(...);
In short, reflection provides you with means to get information on a type. It cannot be used to reference the property of another type (as shown in your last example).
You are on the right track, but you need to go from right to left in your path. So taken you have some nested properties. You first create the nested object, such as:
var objNested = Activator.CreateInstance(objNestedType);
objNestedType.GetProperty(nestedPropertyName).SetValue(objNested, value);
and then you add your newly created object to its 'parent':
var objBase = Activator.CreateInstance(objBaseType);
objBaseType.GetProperty(basePropertyName).SetValue(objBase, objNested);
Arrays are bit different. Reflection expects you to write down the final value when using propertyinfo.SetValue, in case of an array this is the entire array value. In order to do this you can use Array.CreateInstance(typeof(arrayType), arrayLength) to create a new array and use the 'SetValue(object, index)' method to set its contents.
I recently discovered the dynamic-Datatype and it's pretty useful at all for the project I currently work on.
Here is a little snippet of my code:
if (tempDyn != null)
{
termIndex[i] = tempDyn;
}
While termIndex is a dynamic-Array and tempDyn is of dynamic-Datatype.
Before I assign termIndex[i] the Val of tempDyn, it already holds a value. Of type: String. tempDyn is of type object[] but I dont run any operation on the value which could be specific to a certain type.
When the assignment is taking place Runtime throws an exception:
ArrayTypeMismatchException
The exception that is thrown when an attempt is made to store an element of the wrong type within an array.
I initially thought this would be prevented by using dynamic-Datatypes but it makes sense, that the runtime forms the dynamic-Array to an array of type string[] when the first value is entered. (Split is ran first on termIndex)
Is there anyway to prevent this behaviour and to store the "odd" value in termIndex or would I need to work with further variables/dictionaries?
Your array being of compile time type dynamic[] dos not ensure that the array can truly store any kind of value, it just means that the compiler will not do any type check, and that those will only be done at runtime.
An exemple:
dynamic[] array = new dynamic[2];
array[0] = "blah";
array[1] = 1;
This will run just fine, array is instantiated as a "true" dynamic[]
Contrast this:
dynamic[] array = new string[2];
array[0] = "blah";
array[1] = 1; // <-- throws an ArrayTypeMismatchException!
In this case, array really is a string[]. Storing it in a dynamic[] variable just skips the compile time type verifications, but will not magically allow you to store anything in the array.
As a general rule of thumb, you should limit your uses of dynamic. Dynamic variable are a little more expensive in terms of performance, but that's not the main point. The main issue is that by using dynamics where you don't really need them, you abandon all the help the compiler can provide you by statically typing the variables. You also lose nice things like intellisense or autocompletion.
dynamic is a nice feature when dealing with a source that is intrinsically dynamic,a json input for instance, but don't overuse it.
I am not sure what exactly you are trying.
Providing more of your code like the definitions of the variables would help to understand.
But for now it sounds more like you would want to use lists for instead of arrays.
var termIndex = new List<dynamic>();
https://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx
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 been assigned to Convert a VB.NET project to C# and I got stuck. I am using a class called RsiOPCAuto, but I don't think that I'll have to go into to much detail into explaining how it works. Let's just get on with my issue.
So basicly what i do is grabbing an object from my class using this code:
public partial class FrmPartialMain : Form
{
RsiOPCAuto.OPCServer oOpcServer;
public FrmPartialMain()
{
InitializeComponent();
object RsiOPCAuto;
object oOPCList;
oOpcServer = new RsiOPCAuto.OPCServer();
oOPCList = oOpcServer.GetOPCServers();
So far, so good. By adding a watch I can see that oOPCList now have the value {string[1..4]}.
Now I want to put these four strings into a combo box. I do this with a simple for loop:
for (int i = 0; i <= oOPCList.Length; i++)
{
cboServer.Items.Add(oOPCList[i]);
}
Edit: Scratch that, changed this to a much nicer foreach loop.
Even though this object now functions as a string array both the oOPCList.Length and (oOPCList[i]) get errors:
.Length:
Error 1 'object' does not contain a definition for 'Length' and no extension method 'Length' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
oOPCList[i]:
Error 2 Cannot apply indexing with [] to an expression of type 'object'
I bet it's the simplest thing but I just can't see it, help is very much appreciated and if there's anything else you need to know be sure to ask :-)
PS. It might be worth mentioning that I have tried some different ways to convert the object to a string array but I continuously get an error telling me that I can not convert system.string[*] to system.string[].
This is the VB.NET code that I am converting:
Friend Class frmPartialMain
Inherits System.Windows.Forms.Form
Dim oOpcServer As RsiOPCAuto.OPCServer
Private Sub frmPartialMain_Load(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles MyBase.Load
Dim RsiOPCAuto As Object
Dim oOPCList() As Object
Dim i As Integer
oOpcServer = New RsiOPCAuto.OPCServer
oOPCList = oOpcServer.GetOPCServers
For i = LBound(oOPCList) To UBound(oOPCList)
cboServer.Items.Add(oOPCList(i))
Next i
You need to cast the return value of GetOPCServers to an object first, then to an Array, because this method returns a dynamic type. You can't directly cast to a string[] because strong-typed arrays that are not 0-based are not supported by C#. After the cast, you need to call Cast<string> to get a strong typed enumerable, over which you can iterate:
IEnumerable<string> oOPCList;
oOpcServer = new RsiOPCAuto.OPCServer();
oOPCList = ((Array)(object)oOpcServer.GetOPCServers()).Cast<string>();
Furthermore, you would be better off using a foreach loop, because it is a lot more readable:
foreach(var item in oOPCList)
cboServer.Items.Add(item);
The strange cast first to object, then to Array, and then to IEnumerable<string> via Cast<string> is needed because of the following:
GetOPCServers returns a dynamic type. Trying to access that dynamic instance in any way - even via a call to GetType triggers an InvalidCastException. Therefore, it first needs to be cast to object so it no longer is a dynamic type. After that, we can cast it to an Array, the only supported way in C# to work with non-zero-based arrays. But Array is not strong typed, so we append the call to Cast<string> to get a strong typed enumerable.
Firstly you can only access the members of an object available at the reference type. So if you put a string array into a field or variable of type object you'll only be able to access those members defined on object itself (such as ToString)†.
string[*] means the array is an array that is indexed at something other than zero, which usually means it's indexed starting at 1. (I can't remember off hand how to convert these but I will look it up.)
Edit: see this answer on how to work with a non-zero based array in C#.
Whilst it's possible to create and work with such an array, its usage in C# is exceptional so you will have to refer to it via a variable of type Array as string[*] is not valid C#.
† It would still be possible to access them indirectly using Reflection.
You have declared oOPCList as an object which doesnt have a length property and hence cannot be iterated on. What does the oOpcServer.GetOPCServers() return? Is it an Array?
Declare oOPCList as the same type and you can iterate using for or foreach loop
Try this:
foreach(var opc in oOpcServer.GetOPCServers().ToList()) {
cboServer.Items.Add(oOPCList[i]);
}
You get this errors because oOPCList is an object. It doesn't contains lenght nor [] indexers. Use type returned by oOpcServer.GetOPCServers()
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);