I don't understand this square brackets, what i have to create, that this code line is working, only for testing.
filetype = dataBandREP["VRZ.Parent.SIGNATUR"].ToString();
C# can overload operator, including square brackets.
public class Example
{
public string this[string s] // square bracket operator with string argument
{
get
{
return somethingToReturnString;
}
set
{
somethingToSetString = value;
}
}
public string this[int i] // square bracket operator with int argument
{
get
{
return somethingToReturnInt;
}
set
{
somethingToSetInt = value;
}
}
}
The square brackets mean you are referencing a collection and within that collection, you want "VRZ.Parent.SIGNATUR". [] is an indexer with a string as argument.
This code:
filetype = dataBandREP["VRZ.Parent.SIGNATUR"].ToString();
uses the indexer of some sort of collection, referring to an object, then converting it to its string format in order to populate the filetype variable.
A very common usage of this is with arrays and DataColumn collections. String indexers allow you to fetch a value based on, say, a column header, instead of knowing what integral index in the DataTable.Columns collection is associated with the column.
You're getting different behavior when debugging because the validity of "VRZ.Parent.SIGNATUR" as a string indexer has changed, probably because of a change in the actual data source. That's assuming that you're getting a null reference or similar. Without knowing what exception you're getting, we can't help much more than that.
Below syntax also works.. my class is derived from a ReadOnlyDictionary of some type "AttributeValue" and it exports double values. It gives the user an error box when
the value is not found.
public abstract class AttribDoubleReader: IReadOnlyDictionary<string, AttributeValue>
{
public double this[string key] => GetValue(key);
private double GetValue(string key)
{
if (TryGetValue(key, out AttributeValue value))
{
return value.AsDouble();
}
else
{
MessageBox.Show("ERROR: KEY "+ key + " NOT FOUND.");
throw new KeyNotFoundException();
}
}
}
Related
I have the following interface:
public interface IDynamicData: IPersistent
{
string Name { get; }
DataType Type { get; set; }
string InputFormat { get; set; }
dynamic Value { get; }
string DisplayValue { get; }
}
I have a couple of classes that implement this interface, but the one I am interested in is this one:
public class DynamicInput : IDynamicData
{
public string Name { get; private set; }
private DataType _Type;
public DataType Type
{
get { return _Type; }
set
{
_Type = value;
switch (Type)
{
case DataType.String:
Mapping = new StringMap();
break;
case DataType.Numeric:
Mapping = new DoubleMap();
break;
case DataType.DateTime:
Mapping = new DateTimeMap();
break;
default:
Mapping = new StringMap();
break;
}
}
}
[Browsable(false)]
public dynamic Value { get; private set; }
[Browsable(false)]
public string DisplayValue
{
get
{
return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
? Value.ToString(InputFormat)
: Value;
}
}
}
Now, the key here is the dynamic Value property. This value is populated from a string input using the StringMap, DecimalMap, DoubleMap and DateTimeMap classes, where the key method is (similar) to this one:
public override dynamic ProcessInput(string input, int index, string inputFormat, double multiplier, char splitOn = ',')
{
_IsValid = false;
try
{
_Input = input;
double tmp;
_IsValid = Double.TryParse(input.Split(splitOn)[index], out tmp);
return tmp * multiplier;
}
catch
{
_IsValid = false;
return 0;
}
}
This seesm to work fine, and I effectively have a strongly typed Value property at runtime (at least how I understand it). I would like to know when this definition of the type occurs though - when the object is instantiated, or when the Value is assigned to.
I would like to be able to let the user change the type of the Value property at runtime, which involves setting the DataType property to either string/DateTime/double etc. This however, sometimes results in a RuntimeBindingException being thrown at runtime. It doesn't happen all the time, only sometimes, which, I am assuming occurs when the DataType property is changed in between the Value property being set and the DisplayText property being read. That is where the error occurs, in this getter:
public string DisplayValue
{
get
{
return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
? Value.ToString(InputFormat)
: Value;
}
}
I would just like to understand why this happens, and if my analysis is correct, and potentially if there are any workarounds to this problem. If its not possible then thats fine, I will lock down editing of the type of the IDynamicData object.
EDIT
I have experienced this only once - hard to replicate. The instance was, the object was created with DataType.Numeric. I had input strings like "12.345" coming in, every second and being parsed then assigned to the Value property. Then, while I am still receiving data, I changed to DataType.String. This is where the exception occurred. That is, DoubleMap was returning a "dynamic" double, then while input data is still coming in, the StringMap returned a "dynamic" string representation of `12.345'.
I suspect you have a value such as the string "15" but the Type property is set to, for example, DataType.Numeric. In such a case, your code would attempt to call the parameterized overload of ToString(). Because the receiving object is a string, there is no such overload, so the binder throws an exception.
That is a bit speculative. If you could post a working example that demonstrates the problem, or at least describe the specific values you are using when the exception is thrown, we could be more certain of its cause.
If you want to convert a string representation of a number to an int or double representation of that number, you will need to convert the actual value in the Value property. (The actual type of the property is object, by the way, so value routes stored here will be boxed.) The best solution for this would depend somewhat on how you want the calling code to look.
EDIT in response to your edit: the other possibility is that the Value object is a numeric data type such as double, but the Type property is DataType.String. In that case, your code tries to return the double directly, which would cause the binder to fail, just as
string s = 1.2
would fall to compile. In that case, you could use ToString(), thus:
return Value != null && (Type.Equals(DataType.DateTime) || Type.Equals(DataType.Numeric))
? Value.ToString(InputFormat)
: Value.ToString();
That is more of a workaround than a solution, however. I would examine the runtime type of the object and get rid of the Type property.
first off - yes, I had a look at this question: Is object creation in getters bad practice?.
I am also not talking about initializing an object in the accessors / mutators, it is about a specific part of the object I want to be returned in a specific way.
My question is more specific; It does not necessarily only apply to C#, however I am currently looking for a solution to implement in my C# project.
I have a class with a dictionary that maps date objects to a decimal value. In one accessor, I want to return a list of all the keys of the dictionary, another accessors returns the values.
What I also want to have is an accessor that gives me the decimal values in a specific format. It would look something like this:
class Class
{
// Some other properties...
// ....
private Dictionary<DateTime, decimal> dict;
public Class(Dictionary<DateTime, decimal> dict)
{
this.dict = dict;
}
private string FormatTheWayIWant(decimal dt)
{
// Format decimal value.
string s = String.Format("{0:F}", dt);
return s;
}
public ReadOnlyCollection<DateTime> DateTimes
{
get { return new ReadOnlyCollection<DateTime>(this.dict.Keys.ToList()); }
}
public ReadOnlyCollection<decimal> Values
{
get { return new ReadOnlyCollection<decimal>(this.dict.Values.ToList()); }
}
public ReadOnlyCollection<string> FormattedStrings
{
get
{
// Format each decimal value they way I want.
List<string> list = new List<string>();
foreach (decimal dt in dict.Keys)
{
list.Add(FormatTheWayIWant(dt));
}
return new ReadOnlyCollection<string>(list);
}
}
}
This way I can make the following calls (which is my goal!):
DateTime dateTime = DateTimes[0];
decimal s = Values[0];
string formattedS = FormattedStrings[0];
The problem with this approach is that I create a new list everytime I invoke the FormattedStrings accessor, even if I only need one of the formatted strings. I know this is not good practice and can introduce unnecessary performance issues...
The alternatives I thought of are:
I could extend the decimal class and implement a custom ToString()-method.
Or overwrite the KeyValuePair<DateTime, decimal> class and use an indexer in my class.
Or I create a method with a parameter for the index and return just the one formatted string.
Or I could have an own list for the accessor, which gets updated in the set-method for my dictionary everytime I update the dictionary.
The question I have is, is there a way to make this work with an accessor instead of a method, creating custom classes or having strange side effects on other objects when assigning a value?
Thank you in advance.
Ofcourse this can be done with an accessor. You just have to create 3 separate classes for each desired element of your processed collection. Those classes should have their own indexers, so you would be able to access the elements as a list. The difference would be, that they compute each element on demand (wchich is called lazy initialization). So it would go like this (example for your FormattedStrings):
class Class
{
// ...
MyFormattedStrings FormattedStrings
{
get {return new MyFormattedStringsIndexer<string>(this.dict.Values.ToList());}
}
}
class MyFormattedStringsIndexer<T>
{
private IList<T> list; // we take only reference, so there is no overhead
public MyFormattedStringsCollection (IList<T> list)
{
this.list = list;
}
// the indexer:
public T this[int i]
{
get
{
// this is where the lazy stuff happens:
// compute the desired element end return it
}
set
{
// ...
}
}
}
Now you can use your Class like this:
string formattedS = FormattedStrings[5];
and each element you access will be computed as you access it. This solution also has the advantage of separating concerns, so should you ever had to implement different logic for one of your 3 accessors it would be just a matter of extending one of the indexers.
You can read more about indexeres here: http://msdn.microsoft.com/en-us/library/6x16t2tx.aspx
This is VB, but you get the idea...
Public Class Something
Public Property Items As Dictionary(Of DateTime, String)
Public Readonly Property FormattedItem(ByVal index As Int32) As String
' add error checking/handling as appropriate
Return Me.Items.Keys(index).ToString("custom format") ' or whatever your formatting function looks like.
End Property
End Class
It looks like a good candidate for a new class
public class MyObject
{
public DateTime Key {get;set;}
public String Name {get;set;}
public String FormattedString {get;}
}
And then it can be used in any container (List<MyObject>, Dictionary<MyObject>, etc).
Your Dates and Strings property getters are returning a new list on each call. Therefore if a caller does the following:
Class myClass = ...
for(i=0; i<myClass.Strings.Count; i++)
{
var s = myClass.Strings[i];
...
}
then each iteration of the loop will create a new list.
I'm not clear on what you're really trying to achieve here. You are wrapping the dictionary's Keys and Values properties in ReadOnlyCollections. This gives you an indexer, which doesn't have much meaning as the order of the Keys in a Dictionary<TKey, TValue> is unspecified.
Coming (at last!) to your question, if you want to do the formatting in a "lazy" manner, you could create a custom class that implements a readonly IList<string>, and wraps your list of keys (IList<DateTime>). Most of the implementation is boilerplate, and your indexer will do the formatting. You could also cache the formatted values so that you only format once if accessed multiple times. Something like:
public class MyFormattingCollection : IList<string>
{
private IList<decimal> _values;
private IList<string> _formattedValues;
public MyFormattingCollection(IList<DateTime> values)
{
_values = values;
_formattedValues = new string[_values.Count];
}
public string this[int index]
{
get
{
var result = _formattedValues[index];
if (result == null)
{
result = FormatTheWayIWant(_values[index]);
_formattedValues[index] = result;
}
return result;
}
set
{
// Throw: it's a readonly collection
}
}
// Boilerplate implementation of readonly IList<string> ...
}
I want to implement a property that returns a value based on the index it receives. I am not just encapsulating a private array. In fact, the data I will be returning is not stored in any arrays, but instead stored in member objects. This array property will simply be a way to access this data in an indexed way without needing to store it in an indexed way.
According to this article, the following should work:
public double Angles[int i]
{
get { // return a value based on i; }
}
I get the following error, however:
The type or namespace 'i' could not be found (are you missing a using directive or an assembly reference?)
Invalid token ']' in class, struct or interface member declaration
Invalid expression term 'int'
Bad array declarator: To declarate a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.
Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
From those errors, I think it seems that the compiler thinks I am attempting to create an array member. Obviously my syntax is wrong here. Can anybody tell me the correct way to do this?
Named indexers do not exist in C#. You can, however, add Angles as some type of object that has an indexer, i.e.
public class Foo {
public Angles Angles { get { return angles; } }
...
}
...
public class Angles {
public double this[int index] { get { ... } }
...
}
Or if you want the implementation in one class:
public class Foo : IAngles {
public IAngles Angles { get { return this; } }
double IAngles.this[int index] { get { ... } }
}
public interface IAngles {
double this[int index] { get;}
}
The method has to looke like that:
public double this[int i]
{
get { // return a value based on i; }
}
How do square brackets in a method declaration fit in with c#? That is I see when reading up on WPF validation one can use IDataErrorInfo with an example of the following.
public string this[string propertyName]
// Error handling takes place here.
public string this[string propertyName] // <== IE HERE
{
get
// etc
}
}
I note MSDN says "Square brackets ([]) are used for arrays, indexers, and attributes. They can also be used with pointers." So is the above usage a pointer?
This is a standard feature of the C# language called an Indexer. Generally you would use these when writing your own collections, or similar types. Here is a brief (not real world) example.
public class Foo {
private List<int> m_Numbers = new List<int>();
public int this[int index] {
get {
return m_Numbers[index];
}
set {
m_Numbers[index] = value;
}
}
}
class Program {
static void Main() {
Foo foo = new Foo();
foo[0] = 1;
}
}
There's a lot of cool things you can use indexers for if you are creative, it's a really neat feature of the language.
This is a declaration of an Indexer. It's analagous to array indexing. propertyName is a string which the method uses to index into some kind of collection. The method returns the corresponding string from the collection.
Of course, the method could do something else, but that's what the semantics mean.
That would be an indexer property. They're useful on custom collections:
public class MyCustomCollection
{
List<MyObject> _list = new List<MyObject>();
public string this[string name]
{
get { return _list.Single(o => o.Name == name)
.Select(o => o.Description);
}
public string this[int id]
{
get { return _list.Single(o => o.Id == id).Select(o => o.Description);
}
}
And then you can use the collection like:
MyCollection col = new MyCollection();
// Fill the collection
string description = col["Name"];
string description2 = col[2];
I am wondering what type the 'value' keyword in a property takes.
so:
public class Test
{
string _numberAsString;
int _number = -1;
public Test() {}
public string NumberAsString
{
get { return _numberAsString; }
set { _numberAsString= value; }
}
public int Number
{
get { return int.Parse(_numberAsString); }
set { _number = value; }
}
}
//elsewhere
Test t = new Test();
t.Number = 5;
Now, this doesn't compile, as I'd expect. The type of 'value' is determined by the return type of the property, is that correct? I couldn't find anything to that effect, perhaps it's too obvious (I haven't read the language specs, presumably there's something in there).
I ask, because I would like to set the property with a type that is then converted into the type of the getter. I suppose this doesn't really make sense.
It seems I will have to achieve this by creating a couple of methods.
Yes, the type of 'value' is determined by the return type of the property. What exactly are you trying to accomplish? Do you want to be able to set either Number or NumberAsString to a valid value and get a result back out from either property?
If that's the case you need to do something like this:
public class Test
{
string _numberAsString;
int _number = -1;
public Test() {}
public string NumberAsString
{
get { return _numberAsString; }
set { _numberAsString= value; }
}
public int Number
{
get { return int.Parse(_numberAsString); }
set { _numberAsString = value.ToString(); }
}
}
This would allow you to do this:
Test t = new Test();
t.Number = 5;
Console.WriteLine(t.NumberAsString); // should print out "5"
t.NumberAsString = "5";
Console.WriteLine(t.Number); // should print out "5"
You can't have a get and a set for a property that take different types. The only option you have is to store it internally as one type and then in either the get or the set (or both) perform the conversion from one type to another.
The type of the value in the setter is the type of the property - you cannot pass a string to a property that is an int, this must first be parsed to an int.
Strings in .net cannot be coerced into any other type (in the way perl, awk and many other dynamic languages allow) they can only be treated as string, or as their parent class object.
you could do the follwoing:
private int _number;
private string _numberAsString;
public string NumberAsString
{
get { return _numberAsString; }
set { LinkedSet(value); }
}
public int Number
{
get { return _number; }
set { LinkedSet(value); }
}
private void LinkedSet(string s)
{
this._number = int.Parse(s);
this._numberAsString = s;
}
private void LinkedSet(int i)
{
this._numberAsString = i.ToString();
this._number = i;
}
obviously the NumberAsString setter can throw a FormatException the Number setter cannot.
I do not recommend this in general though unless you really need to avoid converting the number to a string and the string to a number on a regular basis (at which point you can make the setters lazy in their evalition of the linked value - albeit changing the semantics of the exception from on set of the string to on get of the int - likely to be at best annoying or at worst a nasty bug.
Why not just do
Test t = new Test();
t.Number = 5;
Console.WriteLine(t.Number.ToString());
It strikes me that you're trying to be crafty for no real reason.
I think you are trying to use a property here when a method would be more appropriate. A property isn't supposed to have any unforeseen side effects, which this would by performing a type conversion on it (if it were possible).
It doesn't make sense, to me, to allow a setter on NumberAsString.
Why not this?:
public class Test
{
int _number = -1;
public Test() {}
public string NumberAsString
{
get { return _number.ToString(); }
}
public int Number
{
get { return _number; }
set { _number= value; }
}
}