Question about language design (arrays and indexing) - c#

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

Related

dynamic.ToString() unexpected behaviour

I'm wondering how does this code work:
dynamic dynaString = 2;
string b = dynaString.ToString();
When this one is not working:
var list = new List<dynamic>();
var liststring = new List<string>();
liststring = list.Select(x => x.ToString()).ToList();
I know I can add Cast<string> after Select statement but that does not explain that behaviour. Why does ToString() on dynamic element work different when called on dynamic variable declared in code than on dynamic variable taken from list in LINQ.
I've looked into method signature of Select and it's:
My guess is that x here is a dynamic variable, so it should behave just like dynaString, but it's not. Intellisense is suggesting me that this x.ToString() returns string:
Anyone got experience with dynamics in C# and can explain me that?
I've also tried this code:
var list = new List<dynamic>();
var liststring = new List<string>();
foreach (dynamic a in list)
{
liststring.Add(a.ToString());
}
It compiles as expected, because again the a is declared as dynamic in foreach statement.
According to dynamic type docs:
The dynamic type indicates that use of the variable and references to its members bypass compile-time type checking. Instead, these operations are resolved at run time.
Type dynamic behaves like type object in most circumstances. In particular, any non-null expression can be converted to the dynamic type. The dynamic type differs from object in that operations that contain expressions of type dynamic are not resolved or type checked by the compiler.
There is no way to infer type from usage in case type checking and/or resolution is bypassed at compile-time.
If you omit generic type parameter it will by default return dynamic type even you call ToString() method. The reason is that any non-null expression can be assigned to dynamic. As dynamic is source, it will be also the result of Select(x => x.ToString()) method call.
On the other hand you can assign dynamic object to string variable as you are calling ToString() which returns string instance.

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.)

var vs Object in C# [duplicate]

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.

What is the syntax for creating a Dictionary with values as instances of Action<T>?

I need to create a Dictionary object as a member field
key = string
value = an instance of Action<T> where T could be different per entry, e.g. long, int, string (a ValueType or a RefType)
However can't get the compiler to agree with me here.. To create a member field it seems to need a fixed T specification. I've passed my limit of struggle time before awareness that 'It shouldn't be this difficult'
Might be a generics noob mistake. Please enlighten..
The usage would be something like this
m_Map.Add("Key1",
new delegate(long l) {Console.Writeline("Woohoo !{0}", l.ToString();));
You can't, basically. How would the compiler know what type you were interested in for any particular entry?
You can't even explain a relationship of Dictionary<Type, Action<T>> where each dictionary entry has a key which is a type and an action which uses that type. Generics just doesn't support that relationship.
If you will know the kind when you try to use it, you can just make it a Dictionary<string, Delegate> and cast the value when you fetch it. Alternatively, you could use Action<object> and live with the boxing and cast you'll end up with.
Note that to use anonymous methods or lambda expressions with just Delegate, you'll need to cast - or write a handy conversion method:
public static Delegate ConvertAction<T>(Action<T> action)
{
return action;
}
That way you can write:
Delegate dlg = ConvertAction((long x) => Console.WriteLine("Got {0}", x));
or in the dictionary context:
var dict = new Dictionary<string, Delegate>();
dict["Key1"] = ConvertAction((long x) => Console.WriteLine("Got {0}", x));
You'll still need to cast to the right type when you fetch the value out of the dictionary again though...
A different tack...
Instead of exposing a dictionary directly, you could encapsulate the dictionary in your own type, and have a generic Add method:
public void Add<T>(string key, Action<T> action)
So it would still be a Dictionary<string, Delegate> behind the scenes, but your type would make sure that it only contained values which were delegates taking a single argument.
With different T per entry, perhaps standardise at Action<object>, and cast inside the actual actions?
static void Main() {
var m_Map = new Dictionary<string, Action<object>>();
m_Map.Add("Key1", obj => Console.WriteLine("Woohoo !{0}", obj));
m_Map.Add("Key2", obj => SomeMethod((int)obj));
m_Map["Key1"](123);
m_Map["Key2"](123);
}
static void SomeMethod(int i) {
Console.WriteLine("SomeMethod: {0}", i);
}

Categories