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();
Related
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);
}
I'm looking for a type/method of collection where I can add an object to a group of objects, then separately change the attributes of that object, and have those changes reflected in the object within the collection.
I've heard that List<T> adds values by reference, so I figured that the reference would be to the same object. In other words, I assumed:
List<string> valuesList = new List<string>();
string initialValue = "Alpha";
valuesList.Add(initialValue);
initialValue = "Bravo";
bool incorrectAssumption = (valuesList[0] == "Bravo");
I had hoped that 'valuesList' would then contain the new value, "Bravo." Tried it out and I realized that the List copies the reference, it doesn't absorb it, so valueList still only has the "Alpha" value. Are there any ways to use a collection as a legitimate handful of the objects they contain?
And in case it helps to see the actual business need....
List<BaseWidget> widgets = new List<BaseWidget>();
DerivedWidget specialWidget = new DerivedWidget();
DerivedWidget extraSpecialWidget = new DerivedWidget();
widgets.Add(specialWidget);
widgets.Add(extraSpecialWidget);
specialWidget.Run();
extraSpecialWidget.Run();
if (!widgets.Any(x => x.RunSuccessfully)) return false;
(Where the Run() method sets the RunSuccessfully property, which I'd like to have reflected in the 'widgets' list.)
============================================================================
UPDATE
As it's been pointed out in the answers and comments, there's a bit of a discrepancy between the business need mock-up and the dry-run example. I'll condense the life-lesson into this: it seems List<objects> have their changes tracked, whereas List<values> don't.
Well. It seems that you don't understand what happens really. Here is great article about .net type internals.
Shortly, what happens in your example with strings:
You create list
You create variable initialValue of string type. Value of this variable stores in special local variables container. Because string is reference type, in container of local variables it contained as a pointer to object.
You create new string "Alpha", storing it in heap, and assign pointer (to this string) to your local variable.
Then you are adding object to list. In your List this object stored as pointer to somewhere.
Then you are changing content of local variable 'initialValue' by assign it to pointer to another string. So, now in local variable 'initialValue' is one pointer, in list is another pointer.
Well, what about solutions?
Wrap your string to some another class. Like this:
class Wrapper<T> {
public T Content {get;set;}
public Wrapper(T content) {
Content = content;
}
}
Usage:
void Main()
{
var valuesList = new List<Wrapper<string>>();
var initialValue = new Wrapper<string>("Alpha");
valuesList.Add(initialValue);
initialValue.Content = "Bravo";
Console.WriteLine(valuesList[0].Content);
}
A bit ugly syntax.
Use clojures:
void Main()
{
List<Func<string>> valuesList = new List<Func<string>>();
string initialValue = "Alpha";
valuesList.Add(() => initialValue);
initialValue = "Bravo";
Console.WriteLine(valuesList[0]() == "Bravo");
}
All references to non-value types will be passed by reference, List<T> or not. String is a value type, however, and will always be passed by value. They are also immutable, so any time you change one you're actually creating a new String.
For your example, you could create a wrapper type to contain your string, and store this in your List<T>.
It seems that your actual business case should work properly, unless they are declared as structs.
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());
When I do a query that returns an anonymous type
var assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new {p.Asset, p.Asset.PropertyTbl};
Can I type the return to anything other than var?
You cannot* return an anonymous type because the caller would not know what type it is and wouldn't be able to use it.
If you want to return the results, you can create objects of a non-anonymous type:
IEnumerable<Foo> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new Foo { Bar = p.Asset, Baz = p.Asset.PropertyTbl};
You can also use the Tuple type in .NET 4 if you don't want to create a custom class for your values.
* This is not strictly true - it is possible but you should avoid doing it. Here is a link anyway if you really want to.
You can use object or dynamic (in .NET 4.0) instead of var but don't expect to find a name to an anonymous type. In your case using var is better as it will preserve the strong typing at least until you leave the scope of the current method.
You could define a new class:
public class AssetProp
{
public virtual string Asset {get;set;}
public virtual string PropertyTbl {get;set;}
}
And then you can return it as that class:
IEnumerable<AssetProp> assets =
from Product p in Session.CreateLinq<Product>()
where bundles.Contains(p.ProductBundle)
select new AssetProp {p.Asset, p.Asset.PropertyTbl};
Not really, since the new {p.Asset, p.Asset.PropertyTbl} code creates an anonymous type. Even using object doesn't really gain you much since you can't cast it to anything useful later on, so you would have to use reflection to access the properties.
Not really. If you cast to object you wont be able to access the properties of your anonymous class.
The var keyword was specifically introduced for dealing with anonymous classes - why would you want to avoid it? If you need to return the data you should name the class.
You can if you use lambda expressions, otherwise you can do a cast but do some good exception handling.
you can also do this (it does relate much to your problem though, because you just move "var" somewhere else, but it's interesting that it recognize those types as same)
var element = new { id = 7 };
List<object> collection = new List<object>();
element = collection.Select(item => new { id = 0 }).First();
Consider the following:
// select a subset of the DataTable
var subset = DataTable.Where(...).Select(row => new
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
// or create a new object
var subset = new {
Id = 1,
Name = "something random",
Email = "name#domain.tld"
};
Is there any way to use the subset variable as a parameter to a method, without it being cast as a plain Object? Can you somehow carry the auto-generated type of the variable?
I am trying to avoid having to create new classes every time I want to pass LINQ subsets to methods.
Random generic approaches are welcome.
No, passing anonymous types about isn't generally a good idea because you lose the type information*. You should create a concrete type and use that instead.
var subset = DataTable.Where(...).Select(row => new SomeType
{
Id = Convert.ToInt32(row["Id"]),
Name = row["Name"].ToString(),
Email = row["Email"].ToString()
});
Alternatively you can use the Tuple type if you are using .NET 4. This is a simple way to create "disposable" types and still get some type-safety.
*Actually there is a workaround, but I regard it is an ugly hack and would advise that you don't do it.
If I need to do this, I use resharper's "Replace Anonymous Type With Named Class" refactoring option. Then you have an appropriate named type to expose over the API, and you haven't had to do any work. This also gives you options to create it immutable (like anonymous types) or mutable, nested vs top-level, etc.
BTW, I don't recommend struct here (from the question).
Another option is to pass the behaviour into the method - i.e. an Action<int,string,string> callback - then do something like:
foreach(item in query) callback(item);
However, I don't like this as it is not obvious that there is a likely error in:
DoSomething(args, (id, email, name) => Email(To: email, Subject: name));
(the error being that it should probably be (id, name, email), if you see what I mean)
You can use a generic method:
public static void Foo<T>(T item)
{
// Do whatever
}
Then if you call
Foo(subset);
the compiler will infer T for you. Whether or not that actually helps you is another matter... it depends on what the method is meant to do. Obviously Foo can't refer to Id, Name, Email etc.
In general, if multiple methods should know about the same members, then you should use a named type. The usual case for passing them to generic methods is where the method really doesn't care about what type is involved, such as in LINQ.
I've made a feature request for C# 5 that we should be able to create types which have all the same features as anonymous types (immutability, equality, hash code generation, ToString dumping) but for simple named types. We'll see if it actually happens...
Anonymous Types don't provide much help outside of the context they where created.
If you need to pass an Anonymous Type to a method, either this method is very generic like (Example)
void PrintAllObjectProperties(object obj);
witch you would use reflection to do the work, or you are doing something wrong.
Here's what I came up with...
Extension method on Object:
public static class ObjectExtensions
{
/// <summary>
/// Cast Object to anonymous type.
/// E.G.: new Object().ToAnonymousType(new { Property = new Type() });
/// </summary>
public static T ToAnonymousType<T>(this Object o, T t)
{
return (T)o;
}
}
Usage:
public void HandleAnonymousTypeAsParameter(Object o)
{
var anonymousType = o.ToAnonymousType(new
{
Id = new Int32(),
Foo = new String(),
Bar = new String()
});
// ... You can do this in even less characters:
var anonymousType = o.ToAnonymousType(new { Id = 0, Foo = "", Bar = "" });
}
HandleAnonymousTypeAsParameter(new
{
Id = 1,
Foo = "foo",
Bar = "bar"
});
Credits goes to John Skeet and Thomas P.