So I asked something similar last week, but I think it was pretty confusing, so Ill try to simplify it.
Say for instance I have a class that contains only properties like this:
public class MyPropertyClass
{
public int IntegerProperty { get; set; }
}
Now suppose I have created another class with an array of MyPropertyClass like this:
public class AnotherPropertyClass
{
public MyPropertyClass[] ArrayProperty { get; set; }
}
Now here is the complicated part.
I need to dynamically create a MyPropertyClass[] somehow. I've been trying it with a List<object> thus far. Then, make a call to InvokeMember with this array. Something like this:
//The list that I am adding elements to elsewhere in the code
List<object> objList = new List<object>();
//Adding a couple elements
objList.Add(new MyPropertyClass());
objList.Add(new MyPropertyClass());
//Create the parameter object array, has to be length one and contain an
//object array casted to MyPropertyClass or it will throw an exception.
object[] ob = new object[1] { objList.ToArray() };
//Instantiate the actual object I want to assign the array to.
object obj = new AnotherPropertyClass();
//The call to InvokeMember
obj.GetType().InvokeMember(
"ArrayProperty",
BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
Type.DefaultBinder,
obj,
ob);
This code will throw an exception. The problem is, objList.ToArray() creates an object[] and when InvokeMember tries to assign it to the MyPropertyClass[], it complains about the type mismatch, even though all of the elements are MyPropertyClass types. Basically what I need is a way to say, "hey, all of the elements in objList.ToArray() are going to be MyPropertyClass" i.e object{MyPropertyClass[]} while letting the actual type be arbitrary, it might not be MyPropertyClass, it could be some other type, I don't know at compile time.
What I have here is only my attempt so far, if you know a different approach i'm all ears. If you want more information, see my old question here:
runtime casting of an object[] to a custom type array
I just think there is little too much extra stuff in there that's not related to the actual problem i'm having.
You can create an array of an unspecified type like this:
Array array = Array.CreateInstance(someType, someSize);
You do it like this:
List<MyPropertyClass> objList = new List<MyPropertyClass>();
objList.Add(new MyPropertyClass());
objList.Add(new MyPropertyClass());
AnotherPropertyClass obj = new AnotherPropertyClass();
obj.GetType().GetProperty("ArrayProperty").SetValue(obj, objList.ToArray());
Related
I'm new with C# OOP, and it's a little bit more difficult than JS to put Objects into Array. This is my first exercise, any help on how to put an object into an array is appreciated.
I was hoping the output be cars = { porsche, mercedes, bmw, punto, ferrari};
What I'm doing wrong?
static void Main(string[] args)
{
// Create 5 Car Objects and add them to Array
var porsche = new Car("Porshe", 340);
var mercedes = new Car("Mercedes", 320);
var bmw = new Car("BMW", 330);
var punto = new Car("Punto", 220);
var ferrari = new Car("Ferrari", 380);
// Cars to array
object[] cars = new object[5];
cars[0] = porsche;
cars[1] = mercedes;
cars[2] = bmw;
cars[3] = punto;
cars[4] = ferrari;
foreach(var car in cars)
{
Console.WriteLine($"some {car}");
}
}
Car
class Car
{
public Car(string model, int speed)
{
Model = model;
Speed = speed;
}
public string Model { get; set; }
public int Speed { get; set; }
public int CalculateSpeed( int speed, int skill)
{
return speed * skill;
}
}
Console Output:
some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
some OOP_Car_Human.Car
As I mentioned in the comments, C# is strongly typed. Instead of creating an array of objects (into which any object of any type can be added), instead, create an array of cars:
Car[] cars = new Car[5];
Now, your array can contain nothing but Car objects (or instances of Car sub-classes). No one can say cars[2] = new Horse("Secretariat"); (something that can be done with a object[] array.
You can also use var instead:
var cars = new Car[5];
That way, you don't have to type the type specification twice. The two statements have completely the same meaning. You can only use var when the type of the right-hand side of the assignment can be deduced by the compiler from context. That type is applied to the variable on the left-hand side.
You can also initialize an array when you create it:
var cars = new Car[] {
porsche,
mercedes,
bmw,
punto,
ferrari,
};
When you do that, you don't have to include the array size in the array constructor expression (you can, but you don't have to).
You can also do this:
var cars = new Car[] {
new Car("Porshe", 340),
new Car("Mercedes", 320),
new Car("BMW", 330),
new Car("Punto", 220),
new Car("Ferrari", 380),
};
You don't use the names porshe, mercedes, etc. other than for the array initialization, so you don't really need them. You can use them (and it likely won't cost any more at runtime, but...)
As #crowcoder has pointed out, you really should add a ToString method:
public override string ToString()
{
return Model;
}
That will make your code behave the way you expect. The Console.WriteLine method, when it's passed a string will output a string. However, if it is passed an object of any other type, it will call ToString on the object. The object class declares ToString as a virtual or overridable method. The object class includes an implementation of ToString, but the only thing it knows about an object is the type of the object, so that is what it uses as the returned string. Since the method is virtual/overridable, sub-classes of object (i.e., just about every type) can override that method and do whatever they'd like. Your expectation was that the car's Model property would be output, so that's what this does.
Other folks are pushing you away from arrays and towards List. There are good reasons to do this. One of them (familiar to Javascript programmers) is that List is stretchy; it will grow as you add things (like a Javascript array does). C# arrays are necessarily fixed size.
One other note. As you found out when you had an array of objects that contained Cars, C#'s type-safety will prevent you from directly calling Car-specific methods on objects that the compiler knows only as objects. In C#, a variable types as object can refer to anything, but it only has a very small number of methods (like ToString) that can be called on it directly (unlike Javascript, where member binding is done at runtime rather than compile time).
If you want to get Javascript-like variable behavior, you can use dynamic as the type (var cars = new dynamic[]{bmw, etc.}). Variables typed dynamic can behave very much like Javascript variables (and there are types that behave nearly exactly like Javascript objects (they derive from Expando)).
If you have an expression like (like you showed): Console.WriteLine($"some {car.Model}");, and car is typed dynamic, then, at runtime, the type of car is examined to determine if it has a Model property. If it does, it is evaluated. If it doesn't, it throws an exception. All this is done at runtime. They error that you saw (CS1061:'object' does not contain a definition for 'Model') happens at compile time. Because of type-safety, a Car is known to have a Model property and no-runtime check needs to be done.
That said, nearly everyone monitoring the C# tag will tell you dont' use dynamic unless you have a really good reason to. C#'s type-safety is its big advantage (and once you get used to it, it just makes sense).
I'd go for using a List.
List<Car> cars = new List<Car>();
cars.Add(porsche);
cars.Add(mercedes);
...
cars.Add(ferrari);
cars.ForEach(car => {
Console.WriteLine($"some {car.Model}");
});
If you want to turn it into an array, use:
cars.ToArray();
For some reasons outside of my control a method of mine needs to be defined to accept one parameter of type object. But i know that the value of this parameter is actually of type List with a generic parameter unknown to me.
I am trying to cast this object to List<object>, but have no idea how to do this without knowing what the exact generic parameter is.
I would like to do something like this:
public static List<object> ConvertToList(object input)
{
if (input.GetType().GetGenericTypeDefinition().IsAssignableFrom(typeof(List<>)))
{
//Of course this does not work, because input might for example be of type List<string>
return (List<object>) input;
}
else
{
return null;
}
}
I know that if I had List<T> instead of object input, it would be quite easy by using:
return input.Cast<object>()
but unfortunately i'm stuck with the object parameter. Any idea how i could solve this problem?
You can't cast it, but you can project it onto a list using IEnumerable and Cast. This will give you a new instance of List<object>. You won't be able to modify the old list but you can work with the new one and modify its elements.
object obj = new List<Whatever>();
List<object> list = ((IEnumerable)obj).Cast<object>().ToList();
Currently I am receiving an array of objects from a database.
object [] sqlResultData = DatabaseCall.Result();
This array of objects needs to be matched to class variables like this
CClassOfVars classVar = new CClassOfVars();
classVar.myProperty = sqlResultData[0];
classVar.myProperty1 = sqlResultData[1];
What i wish to do is pass the list of propertys on the class in order to a function and have the mapping from the object array occur automatically based on the order.
For example:
Method defined like this
FillData(object [] databaseValues, IList<object>())
Called like this
CClassOfVars classVar = new CClassOfVars();
object [] sqlResultData = DatabaseCall.Result();
FillData(sqlResultData, new List<object>(){classVar.myProperty,classVar.myProperty1});
The FillData function would hopefully type cast and set the values of myProperty and myProperty1 to the values in array locations of 0,1 etc...
Something like this
FillData(object [] databaseValues, IList<object> mapMe)
{
for (int i = 0; i < mapMe.Count; i++)
{
mapMe[i] = CastToTheCorrectType(mapMe[i], databaseValues[i]);
}
}
Cast to the correct type could look like this?? I took from here: cast object with a Type variable
public T CastToTheCorrectType<T>(T hackToInferNeededType, object givenObject) where T : class
{
return givenObject as T;
}
How can i pass a list of different object types to all have there values modified and assigned within a different function?
The matter you asking about is dark and difficult to be implemented through just a function. There are frameworks out there dealing with object relational mapping. If it is an option, install and learn some OR/M. If not ... well, there might be some dirty way.
You can use the JSON.NET library to do the heavy lifting for you. It's super easy to use and install through Nuget. My point is as follows.
Construct an anonymous object. Use the property names of the original object.
Fill it with the data from the object array. Spin a loop over the object array...
Serialize the anonymous object.
Deserialize the JSON string into the target type.
At this point, JSON.NET will handle property mapping for you.
List item
E.g. if your target type is Person you might do this:
var x = new
{
FirstName = String.Empty,
LastName = String.Empty
};
var persons = new List<Person>(sqlResultData.Length);
foreach (var record in sqlResultData)
{
x.FirstName = record[0];
x.LastName = record[1];
var s = JsonConvert.SerializeObject(x)`
var personX = JsonConvert.Deserialize<Person>(s);
persons.Add(person);
}
say I have this code:
Dictionary<String, String> myDictionary = new Dictionary<String, String>();
Type[] arguments = myDictionary.GetType().GetGenericArguments();
In my program, myDictionary it's of unknown types (it's an object returned from a deserialized XML), but for the purpose of this question, they are string. I want to create something like this:
Dictionary<arguments[0],arguments[1]> mySecondDictionary = new Dictionary<arguments[0],arguments[1]>();
Obviously, it doesn't work.
I searched on MSDN, and I saw they are using the Activator class, but I don't get it.
Maybe somebody more advanced, could help me a little.
You can use the activator class like you mentioned in order to create objects from given types. The MakeGenericType method allows you to specify an array of Types as the parameters for generic objects, which is what you were trying to simulate.
Dictionary<String, String> myDictionary = new Dictionary<String, String>();
Type[] arguments = myDictionary.GetType().GetGenericArguments();
Type dictToCreate = typeof(Dictionary<,>).MakeGenericType(arguments);
var mySecondDictionary = Activator.CreateInstance(dictToCreate);
The code above is essentially pointless as you know that the dictionary is String,String beforehand but assuming you have a way of detecting the required types elsewhere during runtime, you can use the last two lines to instantiate a dictionary of that type.
There is a problem with this approach.
I will try my best to explain it.
I wrote a program which first serializes a class into XML, then deserializes it back.
Basically, the class it's a generic one, and it contains a List(the same type with the class).
So, the type of the class could be anything, starting from simple types, like string, int, etc to more complex classes, like for example a book class, or a person. After using the XmlSerializer.Deserialize method, and getting the object, I should use Reflection to reconstruct back the object, and access the list. And I can't do it that way.
So, if I have something like:
Type classToCreate = typeof(classToBeSerialized<>).MakeGenericType(arguments);
var reconstructedClass = Activator.CreateInstance(classToCreate);
where classToBeSerialized it's the supposed class(which has the list which I have spoken of), and returnedObject it's the object returned from XmlSerializer.Deserialize, I want to access the list like this:
((reconstructedClass)returnedObject).lista
Basically, I'm using reflection to cast the object to it's source.
I know this is an old thread, but I just needed something similar, and decided to show it, (you know for google).
this is basicly a rewrite of the answer by #user2536272
public object ConstructDictionary(Type KeyType, Type ValueType)
{
Type[] TemplateTypes = new Type[]{KeyType, ValueType};
Type DictionaryType = typeof(Dictionary<,>).MakeGenericType(TemplateTypes);
return Activator.CreateInstance(DictionaryType);
}
public void AddToDictionary(object DictionaryObject, object KeyObject, object ValueObject )
{
Type DictionaryType = DictionaryObject.GetType();
if (!(DictionaryType .IsGenericType && DictionaryType .GetGenericTypeDefinition() == typeof(Dictionary<,>)))
throw new Exception("sorry object is not a dictionary");
Type[] TemplateTypes = DictionaryType.GetGenericArguments();
var add = DictionaryType.GetMethod("Add", new[] { TemplateTypes[0], TemplateTypes[1] });
add.Invoke(DictionaryObject, new object[] { KeyObject, ValueObject });
}
This question already has answers here:
How do I use reflection to call a generic method?
(8 answers)
Closed 9 years ago.
Is it possible to declare an instance of a generic without knowing the type at design-time?
Example:
Int i = 1;
List<typeof(i)> list = new List<typeof(i)>();
where the type of i could be anything, instead of having to do:
List<int> list = new List<int();
If you don't know the type at compile-time, but you want the actual type (i.e. not List<object>) and you're not in a generic method/type with the appropriate type parameter, then you have to use reflection.
To make the reflection simpler, I've sometimes introduced a new generic type or method in my own code, so I can call that by reflection but then just use normal generics after that. For example:
object x = GetObjectFromSomewhere();
// I want to create a List<?> containing the existing
// object, but strongly typed to the "right" type depending
// on the type of the value of x
MethodInfo method = GetType().GetMethod("BuildListHelper");
method = method.MakeGenericMethod(new Type[] { x.GetType() });
object list = method.Invoke(this, new object[] { x });
// Later
public IList<T> BuildListHelper<T>(T item)
{
List<T> list = new List<T>();
list.Add(item);
return list;
}
Of course, you can't do an awful lot with the list afterwards if you don't know the type... that's why this kind of thing often falls down. Not always though - I've used something like the above on a few occasions, where the type system just doesn't quite let me express everything I need to statically.
EDIT: Note that although I'm calling Type.GetMethod in the code above, if you were going to execute it a lot you'd probably want to just call it once - after all, the method isn't going to change. You may be able to make it static (you could in the case above) and you probably want to make it private too. I left it as a public instance method for the simplicity of the GetMethod call in sample code - you'd need to specify the appropriate binding flags otherwise.
If you don't know the type at design-time, I'd say you have a list of OBJECTS (the base class for all other types).
List<object> list = new List<object>();
I think the best you are going to be able to do is something like this:
static void Main(string[] args)
{
int i = 1;
var thelist = CreateList(i);
}
public static List<T> CreateList<T>(T t)
{
return new List<T>();
}
You can also use Activator.CreateInstance. Example code snippet:
public class BaseRepository<T> where T : DataContext
{
protected T _dc;
public BaseRepository(string connectionString)
{
_dc = (T) Activator.CreateInstance(typeof(T), connectionString);
}
public void SubmitChanges()
{
_dc.SubmitChanges();
}
}
If you still want to type .Add(), .Remove(), do foreach etc. you can treat the List as a regular "old" System.Collections.IList,
since this interface is luckily implemented by List<T>.
And since all other posted answers to this question shows pretty much every other possible way to create an instance of a List<T> dynamically,
i will show one last way to do it.
I personally use this method when creating generic instances, when i don't really know nothing about the type at compile time,
and the type must be passed as a string, perhaps coming from the application configuration file.
In this example, T is System.String for simplicity but it could be anything:
Type T = typeof ( string ); // replace with actual T
string typeName = string.Format (
"System.Collections.Generic.List`1[[{0}]], mscorlib", T.AssemblyQualifiedName );
IList list = Activator.CreateInstance ( Type.GetType ( typeName ) )
as IList;
System.Diagnostics.Debug.Assert ( list != null ); //
list.Add ( "string 1" ); // new T
list.Add ( "string 2" ); // new T
foreach ( object item in list )
{
Console.WriteLine ( "item: {0}", item );
}