What does this[string key] mean - c#

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.

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.

NSubstitute throws ArgumentSetWithIncompatibleValueException when out parameters gives back different derived type

I have a Key-value store keyValueDatabase. To request data IKeyValueResult keyValueDatabase.GetKeyValue(string id, out IKeyValue value) has to be called with the id for the requested value. The value is given back through the out parameter as an object derived from IKeyValue. The interfaces looks like this:
public interface IKeyValue
{
string ID { get; set; }
}
//analogue IKeyValueString...
public interface IKeyValueDouble : IKeyValue
{
double Value { get; set; }
}
Now I configure a stub of this key-value store using the code below.
ReturnedKeyValues is a collection of stubs of different types of IKeyValues I created.
IKeyValue keyValue;
keyValueDatabase.GetKeyValue(Arg.Any<string>(),
out Arg.Any<IKeyValue>()).ReturnsForAnyArgs(info =>
{
if (ReturnedKeyValues.Select(keyVal => keyVal.ID).Contains(info[0]))
{
info[1] = ReturnedKeyValues.First(keyVal => keyVal.ID == (string)info[0]);
return okResult;
}
else
{
info[1] = null;
return unavailableResult;
}
});
When using this stub the first time keyValueDatabase.GetKeyValue with an id of let's say 'a' it gives back an out value of type IKeyValueDouble as it should. Now when calling this method a second time with the id 'b' a value of type IKeyValueString should be given back. However an ArgumentSetWithIncompatibleValueException is thrown in this case:
Could not set value of type ObjectProxy_1 to argument 1 (IKeyValue&)
because the types are incompatible.'
Using Returns instead of ReturnsForAnyArgs behaves in the same way. I am using NSubstitute 4.2.0 with .Net-Framework 4.7.
Edit:
In my test I create my own databaste stub using an interface specified through an external library. I had to implement this database in production code.
public interface IDatabase
{
/// <summary>Returns the value of one entry</summary>
/// <param name="id">The entry's ID</param>
/// <param name="value">Returns the value of the entry</param>
/// <returns>The result of the read operation</returns>
IKeyValueResult GetKeyValue(string id, out IKeyValue value);
}
In ReturnedKeyValues is my list of stubbed IKeyValues stored, which should be given back:
private static List<IKeyValue> ReturnedKeyValues = new List<IKeyValue>()
{
createKeyValueA(), createKeyValueB()
};
private static IKeyValue createKeyValueA()
{
var keyVal = Substitute.For<IKeyValueDouble>();
keyVal.ID.Returns("a");
keyVal.Value.Returns(21.31);
return keyVal;
}
private static IKeyValue createKeyValueB()
{
var keyVal = Substitute.For<IKeyValueString>();
keyVal.ID.Returns("b");
keyVal.Value.Returns("GA7713");
return keyVal;
}
Further investigation revealed that the problem is related with reusing the out variable. After assigning outVal the first time it is of type IKeyValueDouble. When it is reused it should be assigned to the type IKeyValueString. However the aforementioned exception is thrown. This happens both when called successionally:
IKeyValue outVal;
keyValueDatabase.GetKeyValue("a", out outVal);
keyValueDatabase.GetKeyValue("b", out outVal);
or when the variable is reused through compiler optimization in a loop:
foreach (string key in keys)
{
...
IKeyValue outVal;
IKeyValueResult success = keyValueDatabase.GetKeyValue(key.ID, out val);
...
}
As a workaround I set the value of the out variable to null before setting it to the actual value:
IKeyValue keyValue;
keyValueDatabase.GetKeyValue(Arg.Any<string>(),
out Arg.Any<IKeyValue>()).ReturnsForAnyArgs(info =>
{
if (ReturnedKeyValues.Select(keyVal => keyVal.ID).Contains(info[0]))
{
//Workarround: Setting the out variable to null before assigning a
//new value fixes the problem
info[1] = null;
info[1] = ReturnedKeyValues.First(keyVal => keyVal.ID == (string)info[0]);
return okResult;
}
else
{
info[1] = null;
return unavailableResult;
}
});
Bug in NSubstitute 3.1.0. Fixed with version 4.2.1

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.

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?

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

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

Categories

Resources