Array of objects - modyfing object's fields C# - c#

I've got such a problem. I'm a beginner in C#.
I have an object array (various classes) and in one place of application I want to modify fields like an age or name. Construction
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
prac[0].age = 21;
}
shouts an error
'object' does not contain a definition for 'age' and no extension method 'age' accepting a first argument of type 'object' could be found
I thought that will be similiar to a Java code, but it isn't. What am I doing wrong?
Regards.

You need to cast your member to the class type that contains the age. I'll just assume that your class name is Person and that is has a age member :
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
((Person)prac[0]).age = 21;
}
Important to note are the brackets : (Person)prac[0] is the cast part, you cast the Object prac[0] to a Person object. The outer brackets ((Person)prac[0]) are there so that the code is taken as a Person object, instead of a regular Object.

First you need to cast the object to the type you're intending to work with.
If you work with type object, it has only a limited amount of properties and methods. To use property age, you first need to cast it to the corresponding type that has that property. For instance something like this:
static Object[] prac = new Object[10];
public static void Main(string[] args)
{
SpecificType myObject = prac[0] as SpecificType; // returns null if not successful
if (myObject != null)
myObject.age = 21;
}
HOWEVER, I'm not convinced you're doing the right thing here. I'd personally avoid type object unless absolutely there would be no other way of doing it (and that is very rare in my code). C# is a strongly-type language and by using object you're prone to errors all over the place.

Object doesn't have property age.
All Object's properties and methods are stated here.

It's an array of objects and as the error message suggests, 'object' does not contain a definition for 'age'
You need to declare your array with the type that has age field or property.And the you can modify it whatever you want. For example:
class Person
{
public string Name { get; set; }
}

You have to use an array of your class instead of Object which is the base type of all classes.
static MyClass[] prac = new MyClass[10];
or you have to cast it:
MyClass mc = (MyClass) prac[0];
mc.age = 21;

Object is the base class for all classes in .Net.
Just cast the required value to the required typed class. Or Create a list with the right type instead of object.

Related

error "does not contain a definition for 'getProperty'" when trying to set property of generic typed object

void myFunc<M>()
{
dynamic uploadReq = (M)Activator.CreateInstance(typeof(M));
uploadReq.getProperty("Credentials").SetValue(null);
}
I have a function where I supply a type, an object of this type is created, and then a property on the object is set to null. I get an error
MyCustomType does not contain a definition for 'getProperty'
How can I fix this?
GetProperty its method of Type. Object has no it.
You can use this way:
call GetProperty from type
set value to object
public static void myFunc<M>()
{
dynamic uploadReq = (M)Activator.CreateInstance(typeof(M));
typeof(M).GetProperty("Credentials").SetValue(uploadReq, null);
}
In this specific snippet of code you don't need dynamic or reflection, because you know the type at compile time, just use the generic version of the CreateInstance method or even better the constructor of the type. This is faster and also provides compile time checks.
void myFunc<M>() where M : new()
{
M uploadReq = new M();
uploadReq.Credentials = null;
}
or
M uploadReq = Activator.CreateInstance<M>();
uploadReq.Credentials = null;

Change variable type dynamicallly

I have an argument in my function which is an object. I would like to change the type of this object in order to have access to the class methods (string, int ...).
I know the convert methods and casts. But I want to keep the same argument name. Like :
public void MyFunction(object test)
{
SpecialConvertFunctionToString(test) // Now test is a string
test.Contains(...) // I can use string methods on
}
I don't know if it's possible ! Thanks !
You can do a cast as or is and then compare.
This will check if test is of type MyClass. If it is, then it casts it as this type into the variable myclassobj. Then you can use the methods, properties of MyClass as normal
if (test is MyClass myclassobj)
{
myclassobj.Name = "new name";
myclasssobj.ExecuteMyMethod();
//etc
}

Unpredictible behaviour in c# dynamic

I've found a bug (feature?) during learning dynamic in C#. Can anyone explain me, why do I have an exception??
static class Program
{
public static void Main(string[] args)
{
dynamic someObj = ConstructSomeObj((Action)(() => Console.WriteLine("wtf")));
var executer = someObj.Execute;
executer(); // shows "wtf"
someObj.Execute(); // throws RuntimeBinderException
Console.ReadKey();
}
static dynamic ConstructSomeObj(dynamic param)
=> new { Execute = param };
}
Note: typeof both exectuer and someObj is dynamic
Let's look at following code:
using System;
using System.Collections.Generic;
public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("first");
// works perfectly!!!
dynamic foo = new { x=(Action)(() => Console.WriteLine("ok")) };
foo.x();
// fails
dynamic foo2 = new { x=(object)(Action)(() => Console.WriteLine("ok2")) };
foo2.x();
}
}
dynamic uses reflection to access objects method and fields and since it cannot know exact types it must rely on type information present in objects on which it operate.
When field x in anonymous type is properly typed as delegate invocation foo.x() works because dynamic can see that field value is delegate.
When you use
static dynamic ConstructSomeObj(dynamic param)
{ return new { x = param }; }
to create anonymous class you created class with field x of type object (dynamic is object behind the scenes). When you call obj.x dynamic sees that field type is an object and it does't bother to check to what exact type this field points. And since object doesn't have Invoke() method like delegates it throws exception. If you change method parameter type to Action it will work.
I guess this decision to check field type instead of type of value that field contains was taken to provide better performance. In other words when you check field type CallSite class generated by dynamic can be cached and reused later.
References:
https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/Binder.cs
https://github.com/mono/mono/blob/ef407901f8fdd9ed8c377dbec8123b5afb932ebb/mcs/class/Microsoft.CSharp/Microsoft.CSharp.RuntimeBinder/CSharpInvokeMemberBinder.cs
EDIT: Checked this on mono, can somebody verify on VS
ok, interesting. This 2 Lines would work:
Task.Run(someObj.Execute);
((Action)someObj.Execute)();
It seems that the compiler does accept the () for dynamic types always and at runtime the CLR only looks 'one level deep'. So you can help here by adding explicit cast or do the cast implicit with the Task.Run(). If this is a feature or a bug!? ... no idea ;-) ...

Force type cast between classes of different namespaces

How Force type cast between classes of different namespaces.
Both namespaces have same class.
You can't cast an object to a type it is not. If it belongs to a different namespace then it is not the same class. You will have to create a converter:
public static Namespace1.SomeClass Convert(Namespace2.SomeClass someClass) {
Namespace1.SomeClass rtn = new Namespace1.SomeClass();
rtn.SomeProp = someClass.SomeProp;
rtn.SomeOtherProp = someClass.SomeOtherProp;
return rtn;
}
you could even use reflection to set all the properties on Namespace1.SomeClass that have the same name as Namespace2.SomeClass.
Also, if you own the code to one of the classes, you can check into overloading explicit and implicit on your class.
You can create generic Converter so you don't have to do this each time you need to cast a different type of objects,
T ConvertObject<T>(object M) where T : class
{
// Serialize the original object to json
// Desarialize the json object to the new type
var obj = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(M));
return obj;
}
// Test ObjectToCast is type Namespace1.Class, obj is Namespace2
Namespace2.Class obj = ConvertObject<Namespace2.Class>(ObjectToCast);
Assuming that both classes are the same this will work.
You can't cast from a Type to a different Type, even if the code of the class is exactly the same.
You can create a Converter capable to convert between the two types, or provide implicit/explicit casts inside both classes implementations or eventually you can try Automapper.
You need to qualify the type:
namespace Foo
{
class Bar {}
}
namespace Baz
{
class Bar {}
}
Foo.Bar x = new Foo.Bar();
Baz.Bar y = (Baz.Bar)x;
Of course, this will fail unless there is a conversion defined.
This is not possible. A type include its namespace as part of its full name.
Its like the town of Springfield: same name but from different states. They are all different.
A possible approach would be to overload the cast operator of one of the type so that they can be cast into another type. It won't be a real cast, as the result will be to create a new object with the same value.
public static explicit operator Massachusetts.Springfield(Illinois.Springfield town)
{
return new Massachusetts.Springfield(town); // or any other code to copy the fields from one type to the other
}
If both classes are serializable, you can serialize the first object to XML, change the "namespace" in the xml and deserialize it again.
The fact that the two classes have the same name doesn't mean anything to the compiler. You may have Foo.Orange and Bar.Orange, but to the compiler it may as well be Apple and Orange. To convert:
namespace Foo
{
public class Orange{}
public static explicit operator Foo.Orange(Bar.Orange) { // conversion code }
}
namespace Bar
{
public class Orange{}
public static explicit operator Bar.Orange(Foo.Orange) { // conversion code }
}
// somewhere else
Foo.Orange o = new Foo.Orange();
Bar.Orange bar = (Bar.Orange)o; // and vice-versa

C# reflection get object from type

I have a Type object.
I want to get the object isntance from this type. (just to use the ToString() method from this object).
see:
public class P
{
public string s;
}
class Program
{
static void Main(string[] args)
{
P p = new P();
p.s = "foobar";
Type t = p.GetType();
P p2 = ((t.ToObjet()) as P).s;
Console.WriteLine(p2.s);
}
}
Activator.CreateInstance is what you want.
Type givenType;
var obj = Activator.CreateInstance(givenType);
...
var obj = Activator.CreateInstance(givenType) as GivenType;
EDIT: Based on your edits, the extension method on Type you want (ToObject) is effectively the code above. It must create a new one because you can't be certain the source object still exists and even with the type, you could hit a scenario where that type has multiple instances.
You cannot get the instance back. The type is shared between all the instances, so what you want is impossible.
For example: if you know that something is an integer, you don't know which exactly value it has. (Integer is your type, value is a concrete instance.)
There is no way to do that. One reason is that GetType will return the same Type instance for all instances of the same type.
You can test this like so:
// this will print "True"
Console.WriteLine(object.ReferenceEquals("one".GetType(), "two".GetType()));
Calling GetType on those two different string instances returns the same Type instance, so it is clearly impossible to get one of them back based only on that Type instance.

Categories

Resources