var vs Object in C# [duplicate] - c#

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Difference between “var” and “object” in C#
I would like to know the difference between var and object.
When to use Var and when to use Object.
Pros and cons of using them.

var is just shorthand for "let the compiler pick the right variable type for me" (compile-time type-inference is the more exact term).
object, on the other hand, is a specific type; all other reference types derive from object, so you can assign anything to a variable of type object.

var is the answer when you find yourself asking, do I really have to type that long type name twice, in e.g.:
Dictionary<string, Func<List<Func<int, int, double>>, IEnumerable<Tuple<double, string>>>> myDict = new Dictionary<string, Func<List<Func<int, int, double>>, IEnumerable<Tuple<double, string>>>>();
Why no friend, you don't. Use var instead:
var myDict = new Dictionary<string, Func<List<Func<int, int, double>>, IEnumerable<Tuple<double, string>>>>();
Now myDict really is a Dictionary<string, Func<List<Func<int, int, double>>, IEnumerable<Tuple<double, string>>>>, so you can add things to it, enumerate it, etc.
If you declared it as object you couldn't do any operations with it that are provided by Dictionary, only the ones valid for all objects.

var is still strongly typed but with object you will have to cast everything.

var foo = "Hello, I am a string!";
// foo is a string, so this compiles
var fooCharArray = foo.ToCharArray();
object bar = foo;
// bar is not a string, so this does not compile
var barCharArray = bar.ToCharArray();
In the first example, the compiler knows that foo is a string and so we can call string methods on foo.
In the second example, we "upcast" the string foo to an object. Now the compiler does not know (because it shouldn't know!) that bar is actually a string, and we cannot call string methods on bar. The compiler will not allow implicit downcasting from an object (or any base type) to a derived type (such as System.String). Its part of compile time type safety rules.

Related

Question about language design (arrays and indexing)

using System;
using System.Collections;
public class Program
{
public static void Main()
{
Hashtable x = new Hashtable();
string[] y = new string[]{ "hello", "world" };
x.Add("msg", y);
//Console.WriteLine(x["msg"][0]); why error?
Console.WriteLine(x["msg"].GetType()); //System.String[]
Console.WriteLine(((string[]) x["msg"])[0]);
}
}
Why i cant access array items like this
Console.WriteLine(x["msg"][0]);//Cannot apply indexing with [] to an expression of type 'object'
if compiler knows that its an array of strings
Console.WriteLine(x["msg"].GetType());//System.String[]
and it forces me to use such an ugly syntax?
Console.WriteLine(((string[]) x["msg"])[0]);
Your hashtable isn't a generic. All it knows is that added values are of type object.
The runtime type of x["msg"] is string[], but its compile-time type is object.
This is the signature of the HashTable indexer: object this[object key] { get; set; }. In other words, at compile time, any object retrieved using the indexer will have compile-time type object.
You can use the generic Dictionary<Tkey, TValue> instead. This will retain the compile-time type information:
var dict = new Dictionary<string, string[]>();
dict.Add("msg", new string[]{ "hello", "world" });
Console.WriteLine(dict["msg"][0]);
It doesn't work because HashTable doesn't know what the type of objects stored in it are. When you get something out of it (e.g. with your x["msg"]) the value of the data returned is going to be of type object. And since object doesn't know how to deal with the indexer operator, trying to force it will result in an error.
It doesn't matter what the underlying data is. What matters is the type of the variable itself is. HashTable returns objects, so without casting you can only do stuff to it what you could normally do with an object variable. This is the nature of using a statically-typed language like C#. (As opposed to a dynamically-typed language like Javascript.)
If, however, you used a generic collection like Dictionary<string, string[]>, you could do this easily. This is because Dictionary uses the generic type parameter to determine what the actual type of the data stored within it is, and so returns values of the correct type.
Dictionary<string, string[]> x = new Dictionary<string, string[]>();
string[] y = new string[]{ "hello", "world" };
x.Add("msg", y);
Console.WriteLine(x["msg"][0]); // Will execute perfectly fine

Why is C# dynamic type static?

While reading and exploring the dynamic keyword I found following line on [MSDN] (in Using Type dynamic (C# Programming Guide)):
The type is a static type, but an object of type dynamic bypasses static type checking. In most cases, it functions like it has type object.
What is the meaning of static in above line and how does it bypass static type checking?
This is static typing:
string foo = "bar";
foo is now a string, so this will cause a compile time error:
foo = 1;
Even if you use var, it's still statically typed:
var foo = "bar"; // foo is now a string
foo = 1; // still a compile time error
Using the dynamic keyword, means the type won't be static and can be changed, so now you can do this:
dynamic foo = "bar";
foo = 1; // this is now fine.
Now, why it says "the type is a static type" is because in many dynamic languages (like Javascript), you can do something like this:
var foo = { bar: 1 };
Which creates an object with a property called "bar", and then you can do this:
foo.la = 2;
Which adds a new property to the object in foo. But if you try the same trick in C#
dynamic foo = new SomeClassThatDoesntHaveABarProperty();
foo.bar = 2; // runtime error
Nor can you delete a property. You can assign any type to a dynamic variable, but you can't change those types themselves.
If you do need that type of functionality, then you'll want to look at ExpandoObject
As your description says, dynamic functions like an object in a lot of cases. You could do this:
dynamic foo = new Foo();
foo = new Bar();
Just as well like this:
object foo = new Foo();
foo = new Bar();
But the difference comes in when you want to use properties or methods. With dynamic, I can do this:
dynamic foo = new Foo();
foo.FooMethod(); // Note: You WILL get a runtime exception if foo doesn't have a FooMethod
But with an object, I'd need to do this:
object foo = new Foo();
((Foo)foo).FooMethod(); // Note: I HAVE to know the type at compile time here
Which I can only do if I already know I can cast the type in foo to a type of Foo at compile time, and if I knew that already, then I could just have use Foo as my type instead of object.
It means that a variable declared as dynamic will stay of type dynamic and cannot be changed to a variable of type int for example. This concept is bypassed though, because you can change the types of objects that the variable holds.
C# is considered as a strongly typed language because variables are statically typed. That means every variable is typed and the C#-compiler can check if the right types are used in the code. In weakly typed language like most script languages the type of variables is dynamic. They can hold any value.

OOP questions, instantiating an object [duplicate]

This question already has answers here:
Use of var keyword in C#
(86 answers)
Closed 8 years ago.
I have an object animal:
class Animal{
}
I want to create an object of Animal, is there a difference between the lines on the class main?
class main{
var myVar = new Animal(); // case 1
Animal myAnimal = new Animal(); // case 2
}
There is no difference. MSDN var description says:
An implicitly typed local variable is strongly typed just as if you had declared the type yourself, but the compiler determines the type.
In other words, it is just a helpful way of writing the same code, with a little help of compiler. It is quite usefull when you are creating long types like:
var dict = new Dictionary<string, List<int>>();
instead of:
Dictionary<string, List<int>> dict = new Dictionary<string, List<int>>();
but was added at the same time as LINQ and anonymous types to make LINQ queries:
var outpus = someList.Where(x => x.SomeData == 0)
.Select(new
{
FieldA = x.SomeField
});
so here compiler determines the anonymous type, you do not have to specify it.
You can read more about it on MSDN.

Reflection c# in a set property

Why can't I use the value word in a set property when i'm trying to get the type of the value?
set
{
Type t = value.GetType();
if (dictionaries[int.Parse(value.GetType().ToString())] == null)
{
dictionaries[int.Parse(value.GetType().ToString())] = new Dictionary<string,t>();
}
}
It doesn't recognize the word t in my Dictionary constructor.
what am I doing wrong? how can I solve it?
You cannot use values or names of types as generic type parameters. Use a method with a generic type parameter instead:
void SetDict<T>(T value)
{
Type t = typeof(T);
if (dictionaries[t.FullName] == null)
{
dictionaries[t.FullName] = new Dictionary<string,T>();
}
}
Instead of using the type name, you can also use the Type value as a key directly for dictionaries:
Dictionary<Type, Dictionary<string,T>> dictionaries;
You can call it without specifying the generic type parameter, because the compiler can infer the type. However, this works only for the static type, not for the runtime type. I.e. you must call the method with an expression of the right type and not through a base type like object.
SetDict("hello"); // ==> string type
SetDict(42); // ==> int type
object obj = "world";
SetDict(obj); // ==> object type, not string type!
Note: Generic type parameters allow you to create strongly typed specialized types and methods at compile time. The advantage of strong typing lies in the fact that the compiler and the IDE can give you information on a type and certify that your code is statically correct AT COMPILE TIME. Creating a generic type at RUNTIME has no advantage, as you won't be able to use its advantages at compile time (or design time, if you prefer). You can as well use a Dictionary<string, object> or the like.
Please see my answer on code review: Type-safe Dictionary for various types. Especially my update to the answer.
You can't use a Type variable when declaring a generic type, you have to use an actual type.
In other words, this won't work:
Type t = ....
var x = new Dictionary<string, t>();
Depending on your class, you could do this:
public class Something<T>
{
public T Value
{
...
set
{
... new Dictionary<string, T>();
}
}
}
but that's not quite the same.
You also got a different problem, this:
int.Parse(value.GetType().ToString())
will not work.
value.GetType().ToString()
will likely produce something like System.Int32 or YourAssembly.NameSpace.SomeType, not a number that can be parsed.
I think you need to take one step back, and figure out what you're trying to accomplish here.

Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>, AnonymousType#1>

I have the following dictionary in a method:
var nmDict = xelem.Descendants(plantNS + "Month").ToDictionary(
k => new Tuple<int, int, string>(int.Parse(k.Ancestors(plantNS + "Year").First().Attribute("Year").Value), Int32.Parse(k.Attribute("Month1").Value), k.Ancestors(plantNS + "Report").First().Attribute("Location").Value.ToString()),
v => {
var detail = v.Descendants(plantNS + "Details").First();
return
new
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
});
I need to return nmDict. The problem is that I cannot figure out how to label my method signature. I have tried the following:
protected IDictionary<XElement, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
The above gives me this error:
Cannot implicitly convert type System.Collections.Generic.Dictionary<System.Tuple<int,int,string>,AnonymousType#1>' to 'System.Collections.Generic.IDictionary<System.Xml.Linq.XElement,System.Xml.Linq.XElement>'. An explicit conversion exists (are you missing a cast?)
protected IDictionary<Tuple, XElement> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
gives me this error:
'System.Tuple': static types cannot be used as type arguments
I do not know what to do.
The short answer: You can't return anonymous types from a function.
The long answer: Your dictionary's value type is anonymous {BaseHours, OvertimeHours} which cannot be returned from a function or passed as an argument (except as an object, but that does nobody any good unless you go through the hassle of reflecting into it). Either define a class/struct with BaseHours and OvertimeHours in it, or use a tuple. The former is probably slightly better because you can keep the names BaseHours and OvertimeHours; with a tuple you just get Value1 and Value2.
If you are using C# 4.0 than you can return the anonymous via dynamic type. So your method signature would look like this
protected IDictionary<Tuple<int,int,string>, dynamic> OvertimereportData(HarvestTargetTimeRangeUTC ranges)
And through the dynamic object you can find the properties at run time.
Hope this will help you.
When you call the ToDictionary method, the resulting dictionary's type has little to do with the type of elements in your source sequence. It's defined entirely by the data types returned by the key and value expressions you supply to the call. For example, if you were to call:
xelem.Descendants(plantNS + "Month").ToDictionary(
k => int.Parse(k.Attribute("Year").Value),
v => k.Attribute("Year).Value
);
You would get an IDictionary<int, string> because that's what your two expressions returned. To return that from a method, you just need to construct the correct type, based on your expressions.
Your first one is easy:
k => new Tuple<int, int, string>(...)
The second one, though, is going to be a problem. The values in your dictionary are of an anonymous type: you return a new { } without specifying a concrete type name for that value. In general, that is going to make it impossible for you to use that dictionary as a return value or parameter. (It can be done, using some very strange-looking generic techniques, but I wouldn't recommend it.)
The first thing you'll need to do, then, is make a concrete type to hold your values, e.g.
public class HoursContainer
{
public string BaseHours { get; set; }
public string OvertimeHouse { get; set; }
}
and change your Linq query appropriately:
var detail = v.Descendants(plantNS + "Details").First();
return new HoursContainer
{
BaseHours = detail.Attribute("BaseHours").Value,
OvertimeHours = detail.Attribute("OvertimeHours").Value
};
Once you've done this, your dictionary will have a concrete type based on the types of things you specified when you created it:
IDictionary<Tuple<int, int, string>, HoursContainer>
(Note: You could also just use another Tuple<int, int> or whatever here, if you wanted, but the resulting generic type would get unwieldy very fast.)

Categories