How can I migrate from dictionary["key"] to ObjectDictionary.key? - c#

It seems like ViewBag.SomeKey works a lot like a php array in the sense that it seems to offer no compiletime checking of key names. I am wondering if there is a one-to-one correspondence with ViewBag and some dictionary class with extra methods, ie if ViewBag.SomeKey works in the same manner as myDictionary["SomeKey"].
Also, I am wondering how I might convert a dictionary into a dynamic object.

ViewBag is a dynamic wrapper around ViewData, which is a dictionary (ViewDataDictionary). Writing ViewBag.SomeKey is the same as ViewData["SomeKey"]
You can initialize it like this :
foreach(var item in myDictionary)
{
ViewData[item.Key] = item.Value;
}
Each item will be available as ViewData["Key"] or ViewBag.Key.

example from msdn
// The class derived from DynamicObject.
public class DynamicDictionary : DynamicObject
{
// The inner dictionary.
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public DynamicDictionary(Dictionary<string, object> d) { dictionary = d; }
public DynamicDictionary() { }
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember( SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
class Program
{
static void Main(string[] args)
{
// Creating a dynamic dictionary.
dynamic person = new DynamicDictionary(/*this can be your dictionary*/);
// Adding new dynamic properties.
// The TrySetMember method is called.
person.FirstName = "Ellen";
person.LastName = "Adams";
// Getting values of the dynamic properties.
// The TryGetMember method is called.
// Note that property names are case-insensitive.
Console.WriteLine(person.firstname + " " + person.lastname);
// Getting the value of the Count property.
// The TryGetMember is not called,
// because the property is defined in the class.
Console.WriteLine( "Number of dynamic properties:" + person.Count);
// The following statement throws an exception at run time.
// There is no "address" property,
// so the TryGetMember method returns false and this causes a
// RuntimeBinderException.
// Console.WriteLine(person.address);
}
}
// This example has the following output:
// Ellen Adams
// Number of dynamic properties: 2

Related

Why I can't put a property name in setter instead of "value" keyword?

When I assign a value in the setter through the value keyword, it works. But why it doesn't work when I try to assign the value through the name of the property, which should hold the same assigned value?
In the following example, I use value keyword in setter, and it works just fine and I get the expected output -
private int i = 1;
public int prop
{
get { return i; }
set { i = value }
}
public void Print()
{
Console.WriteLine(i)
}
static void Main ()
{
Program p = new Program();
p.prop = 5;
Console.WriteLine(p.prop); // outputs 5
p.Print(); // outputs 5
}
But in the following example, I use property name prop instead of value keyword, and it doesn't assign the new value to the i variable -
private int i = 1;
public int prop
{
get { return i; }
set { i = prop }
}
public void Print()
{
Console.WriteLine(i)
}
static void Main ()
{
Program p = new Program();
p.prop = 5;
Console.WriteLine(p.prop); // outputs 1
p.Print(); // outputs 1
}
So, what is the difference? Why I can't use name of the property, which should hold new value, instead of value keyword?
Because it's not the same. This setter:
public int prop
{
get { return i; }
set { i = prop; } // here
}
Will read the current value of prop by calling its getter at the line above it. The keyword value is specifically meant to obtain the value-to-be-set, you can't exchange that for the property's name, because that means something else.
See the docs:
The set accessor resembles a method whose return type is void. It uses an implicit parameter called value, whose type is the type of the property.
[...]
When you assign a value to the property, the set accessor is invoked by using an argument that provides the new value.
The following assumption about your property -
which should hold the same assigned value
is basically wrong. Your property itself is not holding any value at all, it just returns the value of the variable i.
To get a clear picture, keep in mind that C# properties are just syntactic sugar over a pair of methods, and for your property -
public int prop
{
get { return i; }
set { i = value }
}
two methods will be generated behind the scene, which look like -
public int get_prop()
{
return this.i;
}
public void set_prop(int value)
{
this.i = value;
}
As you can see, the value keyword in your property represents a generalized name for the parameter that is passed from outside when you try to set value to a property. So, when you do something like -
p.prop = 5;
basically the set_prop method gets called with 5 as the value for the parameter value.
Now, when you are trying to use your property like -
public int prop
{
get { return i; }
set { i = prop }
}
the generated methods will look like -
public int get_prop()
{
return this.i;
}
public void set_prop(int value)
{
this.i = this.prop;
}
and as you can see, this code is totally ignoring the value of the value parameter passed from outside.
Your code is still setting the value though. It is calling the get method (which returns the value of i) and setting the already set value of i to i again. It is just not making any use of the value that has been passed to it.
"value" is the paramater that is passed in.
prop = 10 will pass in a value of 10 into the setter which you can then grab and assign to your own variable "i"
If you don't use "value" your setter doesn't really do anything.

How to use attributes to affect functions in C#?

According to documentation in C# attribute, It seems that in C#, the Attribute can only be served as a
compile-time metadata storage. You have to use reflection to manipulate it.
...
public class AnimalTypeAttribute : Attribute {
// The constructor is called when the attribute is set.
public AnimalTypeAttribute(Animal pet) {
thePet = pet;
}
// Keep a variable internally ...
protected Animal thePet;
// .. and show a copy to the outside world.
public Animal Pet {
get { return thePet; }
set { thePet = value; }
}
}
...
class DemoClass {
static void Main(string[] args) {
AnimalTypeTestClass testClass = new AnimalTypeTestClass();
Type type = testClass.GetType();
// Iterate through all the methods of the class.
foreach(MethodInfo mInfo in type.GetMethods()) {
// Iterate through all the Attributes for each method.
foreach (Attribute attr in
Attribute.GetCustomAttributes(mInfo)) {
// Check for the AnimalType attribute.
if (attr.GetType() == typeof(AnimalTypeAttribute))
Console.WriteLine(
"Method {0} has a pet {1} attribute.",
mInfo.Name, ((AnimalTypeAttribute)attr).Pet);
}
}
}
}
However, I have noticed that the FlagsAttribute, has not added any variable. Though, it has manipulated/ intercepted the output of ToString() (I guess). How does FlagsAttribute do this? How do I mimic the behavior, or affecting some functions in my custom attributes?
[FlagsAttribute]
enum MultiHue : short {
None = 0,
Black = 1,
Red = 2,
Green = 4,
Blue = 8
};
...
Console.WriteLine( "{0,3} - {1:G}", 3, (MultiHue)3); // output 3 - Black, Red
Reading the code for Enum.cs, we can see that the ToString method calls InternalFormat:
public override string ToString()
{
// Returns the value in a human readable format. For PASCAL style enums who's value maps directly the name of the field is returned.
// For PASCAL style enums who's values do not map directly the decimal value of the field is returned.
// For BitFlags (indicated by the Flags custom attribute): If for each bit that is set in the value there is a corresponding constant
// (a pure power of 2), then the OR string (ie "Red, Yellow") is returned. Otherwise, if the value is zero or if you can't create a string that consists of
// pure powers of 2 OR-ed together, you return a hex value
// Try to see if its one of the enum values, then we return a String back else the value
return InternalFormat((RuntimeType)GetType(), ToUInt64()) ?? ValueToString();
}
private static string InternalFormat(RuntimeType eT, ulong value)
{
Debug.Assert(eT != null);
// These values are sorted by value. Don't change this
TypeValuesAndNames entry = GetCachedValuesAndNames(eT, true);
if (!entry.IsFlag) // Not marked with Flags attribute
{
return Enum.GetEnumName(eT, value);
}
else // These are flags OR'ed together (We treat everything as unsigned types)
{
return InternalFlagsFormat(eT, entry, value);
}
}
And InternalFormat calls GetCachedValuesAndNames to access an information cache.
In this GetCachedValuesAndNames method, we can see that it checks if the FlagsAttribute is defined (bool isFlags = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);):
private static TypeValuesAndNames GetCachedValuesAndNames(RuntimeType enumType, bool getNames)
{
TypeValuesAndNames entry = enumType.GenericCache as TypeValuesAndNames;
if (entry == null || (getNames && entry.Names == null))
{
ulong[] values = null;
string[] names = null;
GetEnumValuesAndNames(
enumType.GetTypeHandleInternal(),
JitHelpers.GetObjectHandleOnStack(ref values),
JitHelpers.GetObjectHandleOnStack(ref names),
getNames);
bool isFlags = enumType.IsDefined(typeof(FlagsAttribute), inherit: false);
entry = new TypeValuesAndNames(isFlags, values, names);
enumType.GenericCache = entry;
}
return entry;
}
So it does indeed use reflection to determine if the FlagsAttribute exists, and adjusts the ToString result accordingly.

How to access methods of subclass in object array C#?

How can I set/get the value of an object in an object array?
Currently I get:
"object does not contain a definition for 'value' and no extension method"
Example C#;
public class myObjClass
{
public int value = 5;
}
public class myObjClass2
{
public float[] pos = new float[2];
}
public void test()
{
myObjClass myObj = new myObjClass();
myObjClass2 myObj2 = new myObjClass2();
object[] objArr = new object[2];
objArr[0] = myObj;
objArr[1] = myObj2;
Debug.Print(myObj.value.ToString());
Debug.Print(objArr[0].value.ToString()); // how?
}
Its because a generic object does not have the property value your class myObjClass has. To fix this you could cast the item to your class like so:
((myObjClass)objArr[0]).value.ToString()
Only do this ^ if you are sure of the type
Instead you could also check it first:
With as:
var item = objArr[0] as myObjClass;
if( item != null ) // Item will be null if its not a 'myObjClass'
{
//Do stuff with item
}
Or with is:
if( objArr[0] is myObjClass )
{
var item = (myObjClass)objArr[0];
//Do stuff with item
}
When using an object array you have to cast to the real type (here: myObjClass) before accessing the fields:
You can access the object like this
((myObjClass)objArr[0]).value
but I would not recommend. CanĀ“t you have your array to be the concrete type
var array = new myObjClass[42]
A compact safe alternative to retrieve the value is
(objArr[0] as myObjClass)?.value
You need to cast object to known type which is myObjClass, like:
((myObjClass)objArr[0]).value.ToString();
Or you can use reflection
var valueString = objArr[0].GetType().GetProperty("value").GetValue(objArr[0]);
Debug.Print(valueString.ToString());
Hope helps,
Technically you can put it as
Debug.Print((objArr[0] as myObjClass)?.value.ToString());
We try casting objArr[0] as myObjClass and if succeed get value and turn it to string. If objArr[0] is not myObjClass we return null as a string
However, a much better way is to implement ToString() in both classes of interest:
public class myObjClass
{
public int value = 5;
public override string ToString() {
// When debugging we want to know "value"
return value.ToString();
}
}
public class myObjClass2
{
public float[] pos = new float[2];
public override string ToString() {
// When debugging we want to know "pos[0]" and "pos[1]" values
return $"{pos[0]} : {pos[1]}";
}
}
And then put an easy
// Just print out debug info (we don't want to know the actual objArr[0] class)
Debug.Print(objArr[0].ToString());
You have a single object, that indeed is an instance of myObjClass, and has a value field, but you have two references to it.
One (myObj) is known to the compiler to be of type myObjClass, and it can guarantee that it has a value field.
The other (objArr[0]) is only known to the compiler to be of type object, and it cannot guarantee that it has a value field.
For example, you could do:
objArr[0] = (random.Next() > 0.5) : myObj ? myObj2
where we're gonna decide at runtime, based on the value of a random number, which will be the type of the actual object at objArr[0].
So, if this was allowed, half of the time objArr[0].value would be correct, and half of the time it will be an error.

What does this[string key] mean

I looked at IRequestCookieCollection code from Microsoft.AspNetCore.Http assembly:
//
// Summary:
// Represents the HttpRequest cookie collection
[DefaultMember("Item")]
public interface IRequestCookieCollection : IEnumerable<KeyValuePair<string, string>>, IEnumerable
{
//
// Summary:
// Gets the value with the specified key.
//
// Parameters:
// key:
// The key of the value to get.
//
// Returns:
// The element with the specified key, or string.Empty if the key is not present.
//
// Exceptions:
// T:System.ArgumentNullException:
// key is null.
//
// Remarks:
// Microsoft.AspNetCore.Http.IRequestCookieCollection has a different indexer contract
// than System.Collections.Generic.IDictionary`2, as it will return string.Empty
// for missing entries rather than throwing an Exception.
string this[string key] { get; }
//
// Summary:
// Gets the number of elements contained in the Microsoft.AspNetCore.Http.IRequestCookieCollection.
//
// Returns:
// The number of elements contained in the Microsoft.AspNetCore.Http.IRequestCookieCollection.
int Count { get; }
//
// Summary:
// Gets an System.Collections.Generic.ICollection`1 containing the keys of the Microsoft.AspNetCore.Http.IRequestCookieCollection.
//
// Returns:
// An System.Collections.Generic.ICollection`1 containing the keys of the object
// that implements Microsoft.AspNetCore.Http.IRequestCookieCollection.
ICollection<string> Keys { get; }
//
// Summary:
// Determines whether the Microsoft.AspNetCore.Http.IRequestCookieCollection contains
// an element with the specified key.
//
// Parameters:
// key:
// The key to locate in the Microsoft.AspNetCore.Http.IRequestCookieCollection.
//
// Returns:
// true if the Microsoft.AspNetCore.Http.IRequestCookieCollection contains an element
// with the key; otherwise, false.
//
// Exceptions:
// T:System.ArgumentNullException:
// key is null.
bool ContainsKey(string key);
//
// Summary:
// Gets the value associated with the specified key.
//
// Parameters:
// key:
// The key of the value to get.
//
// value:
// The key of the value to get. When this method returns, the value associated with
// the specified key, if the key is found; otherwise, the default value for the
// type of the value parameter. This parameter is passed uninitialized.
//
// Returns:
// true if the object that implements Microsoft.AspNetCore.Http.IRequestCookieCollection
// contains an element with the specified key; otherwise, false.
//
// Exceptions:
// T:System.ArgumentNullException:
// key is null.
bool TryGetValue(string key, out string value);
}
and could not understand what the statement
this[string key]
means. Could someone explain me please.
It's an indexer. It defines an indexed property that can be used to access a collection of the object by using objectName["key"] like for example a Dictionary<string,T>.
The implementation could look something like this:
string this[string key]
{
get{return _internalDictionary[key];}
}
Or this:
string this[string key]
{
get
{
switch(key)
{
case "Length":
return this.Length;
case "Timeout":
return this.Timeout.ToString();
case "Version":
return "1.5.0";
}
return null;
}
}
It's just like a method but different
This is really just a special kind of function. For example imagine you had this class:
class MyClass {
public string GetValue(string name) {
switch(key)
{
case "Name":
return "John";
case "Age":
return 30;
}
}
}
The way you would call this code would of course be this:
// Calling a regular method
var instance = new MyClass();
var value = instance.GetValue("Name");
Console.WriteLine(value);
// Output: John
Now change a couple of things so that you are using the "indexer" syntax instead.
Instead of using the method name "GetValue", use the "this" keyword.
Instead of parenthesis around your parameters, use square brackets
Applying those steps:
string GetValue(string name) becomes
string this[string name]
To make it a little easier to envision imagine that your original function instead of being called GetValue() was called This(), then:
string This(string name) becomes
string this[string name]
Full code:
class MyClass {
// public string GetValue(string name) {
public string this[string name] {
switch(key)
{
case "Name":
return "John";
case "Age":
return 30;
}
}
}
In terms of calling your indexer, you drop the function name and again use square brackets instead of parenthesis. So that instance.GetValue("Name") becomes instance["Name"].
Full code:
// Calling a regular method
var instance = new MyClass();
// Remove the dot (.) and the function name
// Instead of parenthesis use square brackets
// var value = instance.GetValue("Name");
var value = instance["Name"];
Console.WriteLine(value);
// Output: John
When should you use an indexer instead of a method?
Whenever you want. Whenever you feel it makes sense. It's usually used when an object stores dynamic keyed values like Dictionary<TKey,TValue>, or when you want your object to behave like an array like List.
It is an Indexer which allows an object to be indexed like an array.
public class MyIndexer
{
private string[] myData;
public string this[int ind]
{
get
{
return myData[ind];
}
set
{
myData[ind] = value;
}
}
}
public class UseIndex
{
public void UseIndexer()
{
MyIndexer ind = new MyIndexer();
ind[1] = "Value 1";
ind[2] = "Value 2";
ind[3] = "Value 3";
ind[4] = "Value 4";
ind[5] = "Value 5";
}
}
It means the implementing object will be a collection indexed on on a string. As for example a Dictionary.

StackOverflowException from a simplest type extends DynamicObject

I've met a strange issue from a type extends DynamicObject. I even tried the sample from MSDN:
// The class derived from DynamicObject.
public class DynamicDictionary : DynamicObject
{
// The inner dictionary.
Dictionary<string, object> dictionary
= new Dictionary<string, object>();
// This property returns the number of elements
// in the inner dictionary.
public int Count
{
get
{
return dictionary.Count;
}
}
// If you try to get a value of a property
// not defined in the class, this method is called.
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
// If you try to set a value of a property that is
// not defined in the class, this method is called.
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
}
Usage:
dynamic d = new DynamicDictionary();
d.FirstName = "Jeff"; // stack overflow
The code works find with a new simple console, but it just throws StackOverflowException from a huge WPF application. In the WPF we have other dynamic code using ExpandoObject, but it's failed for DynamicObject:
Both the WPF project and a console are .NET 4.0 (Full Profile). Can someone share some idea about that?

Categories

Resources