Recommended way to map between JavaScript sparse array and C# (sparse)array? - c#

I am trying to map a JavaScript sparse array to a C# representation.
What is the recommended way of doing this?
It am considering using a dictionary containing the list of oridinals that contained a value in the original array.
Any other ideas?
thanks!

NOTE
I've come up with two .NET solutions to this scenario. Because both solutions require the same JavaScript code, I've only included the JavaScript code for the 2 solutions in this answer.
Now on to the answer...
EDIT Note: I apologize for not completely understanding your question at first. I never heard the term "Sparse Array" used before, so I had to look it up and found the text book definition from Wikipedia, which isn't quite what you were describing and, as far as usage I've seen elsewhere since then, doesn't seem to be what you were describing. It does make sense to use it in this way however.
Thinking about this scenario more has driven me to come up with a solution. As you mentioned, C# (and .NET in general) has no concept of undefined, other than null.
From what I understand, you're looking to be able to represent three different things in your array:
A valid value for the array element
A null value for the array element
The concept of an "undefined" array element
As you pointed out, C# has no concept of "undefined", other than null. To .NET, undefined would be the same as null and it probably should be kept that way. But since you obviously need a way to represent this anyway (I'm assuming for some strange business rule), I tried to come up with an implementation that will work. I'd strongly recommend not doing this though!
The JavaScript Side
The first challenge is the act of serializing the array in JavaScript. When converting an array to JSON format, undefined elements in an array are automatically converted to null. If you call JSON.stringify(...), this will happen:
var array = [73,42,undefined,null,23];
var json = JSON.stringify(array);
if(json === "[73,42,null,null,23]")
alert('I am always true!');
The example above shows that undefined elements in the array are serialized as "null". If you really need to store undefined, you'd have to write a conversion method that will manually serialize arrays to have undefined elements. The ideal solution would result in this JSON:
"[73,42,undefined,null,23]"
This will not work however. Neither the .NET JavaScriptSerializer, or JSON.parse(...) can parse this string (although JavaScript's eval(...) method will work). What we need is a way to represent "undefined" that will serialize using standard JSON methods, and can be understood by .NET's JavaScriptSerializer. The trick to doing this is coming up with an actual object to represent undefined. To represent this, I used this JSON string:
"{undefined:null}"
An object whose only property is called "undefined", and whose value is null. This most likely will not exist in any object in JavaScript code so I'm using this as I consider it a "unique" enough flag to represent our non-existent "undefined" array element.
To serialize JSON like this, you need to provide a replacer that will do the job, so here is how you'd do that:
var arr = [73,42,undefined,null,23];
var json = JSON.stringify(arr, function(key, value) {
jsonArray = value;
if(value instanceof Array) {
var jsonArray = "[";
for(var i = 0; i < value.length; i++) {
var val = value[i];
if(typeof val === "undefined") {
jsonArray += "{undefined:null}";
} else {
jsonArray += JSON.stringify(value[i]);
}
if(i < value.length - 1) {
jsonArray += ",";
}
}
jsonArray += "]";
if(key != null && key != "") {
return key + ":" + jsonArray;
} else {
return jsonArray;
}
}
if(key != null && key != "") {
return key + ":" + JSON.stringify(jsonArray);
} else {
return JSON.stringify(jsonArray);
}
});
This will get you a JSON string that looks like this:
"[73,42,{undefined:null},null,23]"
The downside to this is that once it is deserialized, the undefined array element is no longer undefined, but another object. This means that your parser will have to handle this specially. Make sure that you don't try to use this in any JSON parser that isn't aware of the completely made up "undefined" object. The next step is handle it in C#.
The C# Side
The challenge here is how to represent Undefined values. The solution below opts to treat undefined indexes as "non-existent" in an array. My other solution creates a wrapper similar to the Nullable<T> wrapper for structs.
Create a SparseArray<T> Dictionary Wrapper
I created a SparseArray<T> class that can be used just like a normal array in .NET. The difference between this class & a normal array is that when you access an array element which is undefined, it throws a custom IndexNotFoundException. You can avoid throwing this exception by first checking if the element is defined by calling SparseArray<T>.ContainsIndex(index) to check if it has that index.
Internally it uses a Dictionary, as you mentioned in your question. When you initialize it, first the constructor takes the JSON string and runs it through a JavaScriptSerializer.
It then takes the deserialized array and begins to add each array element to its _Array dictionary. As it adds elemnts, it looks for the {undefined:null} object we defined in JavaScript when we "strungified" it (not sure if that's the correct past tense there...). If it sees this object, the index is skipped over. The length of the array will increment as undefined values are found, however their index is skipped over.
Since the class' code is rather long, I'll put the usage example first:
string json = "[4,5,null,62,{undefined:null},1,68,null, 3]";
SparseArray<int?> arr = new SparseArray<int?>(json);
In a for { } loop, you'll need to check if the array contains each index before accessing it. In a foreach { } loop, the enumerator holds only defined values, so you won't need to worry about the occurrence of undefined values.
Here is the code for my SparseArray<T> class:
[DebuggerDisplay("Count = {Count}")]
public class SparseArray<T>: IList<T>
{
Dictionary<int, T> _Array = new Dictionary<int, T>();
int _Length = 0;
public SparseArray(string jsonArray)
{
var jss = new JavaScriptSerializer();
var objs = jss.Deserialize<object[]>(jsonArray);
for (int i = 0; i < objs.Length; i++)
{
if (objs[i] is Dictionary<string, object>)
{
// If the undefined object {undefined:null} is found, don't add the element
var undefined = (Dictionary<string, object>)objs[i];
if (undefined.ContainsKey("undefined") && undefined["undefined"] == null)
{
_Length++;
continue;
}
}
T val;
// The object being must be serializable by the JavaScriptSerializer
// Or at the very least, be convertible from one type to another
// by implementing IConvertible.
try
{
val = (T)objs[i];
}
catch (InvalidCastException)
{
val = (T)Convert.ChangeType(objs[i], typeof(T));
}
_Array.Add(_Length, val);
_Length++;
}
}
public SparseArray(int length)
{
// Initializes the array so it behaves the same way as a standard array when initialized.
for (int i = 0; i < length; i++)
{
_Array.Add(i, default(T));
}
_Length = length;
}
public bool ContainsIndex(int index)
{
return _Array.ContainsKey(index);
}
#region IList<T> Members
public int IndexOf(T item)
{
foreach (KeyValuePair<int, T> pair in _Array)
{
if (pair.Value.Equals(item))
return pair.Key;
}
return -1;
}
public T this[int index]
{
get {
if (_Array.ContainsKey(index))
return _Array[index];
else
throw new IndexNotFoundException(index);
}
set { _Array[index] = value; }
}
public void Insert(int index, T item)
{
throw new NotImplementedException();
}
public void RemoveAt(int index)
{
throw new NotImplementedException();
}
#endregion
#region ICollection<T> Members
public void Add(T item)
{
_Array.Add(_Length, item);
_Length++;
}
public void Clear()
{
_Array.Clear();
_Length = 0;
}
public bool Contains(T item)
{
return _Array.ContainsValue(item);
}
public int Count
{
get { return _Length; }
}
public bool IsReadOnly
{
get { return false; }
}
public bool Remove(T item)
{
throw new NotImplementedException();
}
public void CopyTo(T[] array, int arrayIndex)
{
throw new NotImplementedException();
}
#endregion
#region IEnumerable<T> Members
public IEnumerator<T> GetEnumerator()
{
return _Array.Values.GetEnumerator();
}
#endregion
#region IEnumerable Members
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return _Array.Values.GetEnumerator();
}
#endregion
}
And the exception needed to use this class:
public class IndexNotFoundException:Exception
{
public IndexNotFoundException() { }
public IndexNotFoundException(int index)
: base(string.Format("Array is undefined at position [{0}]", index))
{
}
}

NOTE
I've come up with two .NET solutions to this scenario. I've kept them in separate answers so they could be voted on based on which solution is more favorable, and so that the author may choose the most favorable solution as the "Accepted Answer". Because both solutions require the same JavaScript code, I've only included the JavaScript code for the 2 solutions in my other answer. If this answer is marked as accepted, I'll include my JavaScript solution in this answer so that it will be included with the answer that comes logically first on the page.
Now on to the answer...
To start, I want to repeat what I mentioned in my other solution, since it is important to mention:
As you pointed out, C# has no concept of "undefined", other than null. To .NET, undefined would be the same as null and it probably should be kept that way. But since you obviously need a way to represent this anyway (I'm assuming for some strange business rule), I tried to come up with an implementation that will work. I'd strongly recommend not doing this though!
For this solution, I created a wrapper class called Undefined<T>. It works similarly to .NET's native Nullable<T>. The downside to this is that, because .NET has no concept of "undefined", it was difficult to decide how to handle accessing the value of the object. I chose to throw an exception if you try to cast an undefined object when it is undefined.
With this solution, you have an actual array where every element exists. Although every element exists, you can't actually get the value of every element. The class I created behaves like Nullable<T> in every way, except that when you try to cast an undefined object, or get its Value, this class throws an exception. You need to call IsDefined to make sure you can use the Value before you actually try to use it.
[DebuggerDisplay("IsDefined:{IsDefined}, Value:{_Value}")]
public sealed class Undefined<T>
{
public static Undefined<T>[] DeserializeArray(string jsonArray)
{
var jss = new JavaScriptSerializer();
var objs = jss.Deserialize<object[]>(jsonArray);
var undefinedArray = new Undefined<T>[objs.Length];
for (int i = 0; i < objs.Length; i++)
{
if (objs[i] is Dictionary<string, object>)
{
var undefined = (Dictionary<string, object>)objs[i];
if (undefined.ContainsKey("undefined") && undefined["undefined"] == null)
{
undefinedArray[i] = new Undefined<T>(default(T), false);
continue;
}
}
T val;
// The object being must be serializable by the JavaScriptSerializer
// Or at the very least, be convertible from one type to another
// by implementing IConvertible.
try
{
val = (T)objs[i];
}
catch (InvalidCastException)
{
val = (T)Convert.ChangeType(objs[i], typeof(T));
}
undefinedArray[i] = new Undefined<T>(val, true);
}
return undefinedArray;
}
private Undefined(T value, bool isDefined)
{
Value = value;
IsDefined = isDefined;
}
public static explicit operator T(Undefined<T> value)
{
if (!value.IsDefined)
throw new InvalidCastException("Value is undefined. Unable to cast.");
return value.Value;
}
public bool IsDefined { get; private set; }
private T _Value;
public T Value
{
get
{
if (IsDefined)
return _Value;
throw new Exception("Value is undefined.");
}
private set { _Value = value; }
}
public override bool Equals(object other)
{
Undefined<T> o = other as Undefined<T>;
if (o == null)
return false;
if ((!this.IsDefined && o.IsDefined) || this.IsDefined && !o.IsDefined)
return false;
return this.Value.Equals(o.Value);
}
public override int GetHashCode()
{
if (IsDefined)
return Value.GetHashCode();
return base.GetHashCode();
}
public T GetValueOrDefault()
{
return GetValueOrDefault(default(T));
}
public T GetValueOrDefault(T defaultValue)
{
if (IsDefined)
return Value;
return defaultValue;
}
public override string ToString()
{
if (IsDefined)
Value.ToString();
return base.ToString();
}
}

Related

How to handle ProblemDetails response from API in .NET MAUI app [duplicate]

I've looked through many questions that are similar to this, but none of them really touched on what I precisely want to do. What I am trying to do is read from an external source a list of variables that also include their data type into a string array:
Example:
ID/Key Type Value/Data;
varName1 bool true;
varName2 string str;
varName3 int 5;
I then store these are objects into a dictionary as objects containing several strings, with the ID also serving as the key.
What I want to do is now create a method that uses a switch statement that casts the string into the correct datatype, and returns it without having to specify anything in the method call. The function should look something like this:
public ??? Method(string key)
{
if(dictionary.ContainsKey(ID))
{
Var temp = dictionary[ID];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
The method call should look something like this:
int x = Method(string key);
string word = Method(string key);
bool isTrue = Method(string key);
Maybe I've missed something, but I have yet to find something that really does something quite like this. Any and all thoughts about this are welcome as well.
In C# 7 you have the option to return multiple values from a method like this:
public (string SomeString, int SomeInt) DoSomething() { ... }
You can get the values like this:
var result = DoSomething();
Console.WriteLine(result.SomeString);
Console.WriteLine(result.SomeInt.ToString());
Or
(var someString, var someInt) = DoSomething();
Console.WriteLine(someString);
Console.WriteLine(someInt.ToString());
This works below the surface with a Tuple and you are not restricted to only 2 values. I don't know how many you can return but I suggest when you need to return that many values, create a class.
More info: https://blogs.msdn.microsoft.com/dotnet/2016/08/24/whats-new-in-csharp-7-0/
Update
I believe a lot of people are arriving at this question because they're looking for ways to return multiple values generally, not necessarily for the purposes given in the original question. If this is what you want, there are a few options to choose from.
If the combination of your returned types represents a concept that may be useful outside of your method call, consider creating a type to represent that concept. C#'s records provide a nice, concise way to do that:
public record ExtractedValue(bool? BooleanValue, string? StringValue, int? IntValue);
public ExtractedValue Method(string key)
{
...
}
If this is the only place these values will appear together, and it's not really worth coming up with a named type to represent the values, you can also use a Value Tuple. Just be aware that there are some behavioral implications that might bite you if you plan to use the type for things like serialization.
public (bool? BooleanValue, string? StringValue, int? IntValue) Method(string key)
{
...
}
Original Answer
The compiler has no way to distinguish between the three method calls you've provided, because they all look like Method(key);
One option is to return an object and then expect the consuming code to cast it to what they want:
public object Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = (int) Method(key);
string word = (string) Method(key);
bool isTrue = (bool) Method(key);
You could also use the dynamic keyword to make the cast implicit:
public dynamic Method(string key)
{
if(dictionary.ContainsKey(key))
{
var temp = dictionary[key];
switch (temp.Type)
{
case "bool":
return Convert.ToBoolean(temp.Value);
case "int"
return Convert.ToInt(temp.Value);
case "string"
return temp.Value;
}
}
return "NULL";
}
...
int x = Method(key);
string word = Method(key);
bool isTrue = Method(key);
However, dynamic is a very powerful concept, and it's easy for it to get out of hand, so you have to be really careful with that.
It seems to me that you're expecting your calling code to know which type of object it's expecting to get for each key. It seems like maybe the best approach is to just let the user supply that information:
public T Method<T>(string key)
{
if(dictionary.ContainsKey(key))
return (T) Convert.ChangeType(dictionary[key].Value, typeof(T));
return default(T);
}
...
int x = Method<int>(key);
string word = Method<string>(key);
bool isTrue = Method<bool>(key);
That way, there's no need to track the Type value in your dictionary objects in the first place.
The return type of a function must be typed. As with any other variable or operation, any type that inherits from the specified type is a valid return value (which is why object allows anything as a value).
Personally i dont think it is useful to make one method with multiple return types but if you really want to have one method with multiple return types, you could use the dynamic type in .NET 4.0:
private static void Main(string[] args)
{
int x = Method("varName3");
string word = Method("varName2");
bool isTrue = Method("varName1");
}
private static dynamic Method(string key)
{
var dictionary = new Dictionary<string, KeyValuePair<Type, object>>()
{
{ "varName1", new KeyValuePair<Type, object>(typeof(bool), false) },
{ "varName2", new KeyValuePair<Type, object>(typeof(string), "str") },
{ "varName3", new KeyValuePair<Type, object>(typeof(int), 5) },
};
if (dictionary.ContainsKey(key))
{
return dictionary[key].Value;
}
return null;
}
Hope it helps

How to refactor the pervasive if statement for type check

I'm work with a legacy system which has been around ten years, in it one of the basic data structure is defined like below:
[Serializable()]
public class DataClass
{
private Array _values;
private readonly Type _valueType;
public DataClass(Array tmpArray, Type tmpType)
{
_values = tmpArray;
_valueType = tmpType;
}
public Array GetValues()
{
return _values;
}
public Type ValueType
{
get { return _valueType; }
}
public void SetValues(Array newValues, int fromIndex)
{
// 1. type check, if _values and newValues don't share same data type, throws an exception
// 2. length check
if (fromIndex + newValues >= _values.Length)
throws new InvalidDataException();
// 3. set values
for (var i = fromIndex; i < newValues.Length; i++)
_values.SetValue(newValues.GetValue(i - fromIndex), i);
}
...blahblah
}
I believe the initiative was they want to support different data types using only one class, e.g.
new DataClass(new int[]{1,2,3,4}, typeof(int));
new DataClass(new float[]{1f,2f,3f,4f}, typeof(float));
Now I want to init the DataClass with default values, after profiling I found that the API SetValues is quite slow for longer arrays (boxing and unboxing I believe) and makes the program less responsive, I decided to use Generic and lots of if else statement for speeding up, e.g.:
void InitValues(DataClass data)
{
if (data.ValueType == typeof(int))
InitWith(data, -1);
else
if (data.ValueType == typeof(double))
InitWith(data, -9.99d);
...blahblah
}
void InitWith<T>(DataClass data, T defaultValue)
{
// much faster
var array = (T[])data.GetValues();
for (var i = 0; i < array.Length; i++)
array[i] = defaultValue;
}
Yet I got plenty of performance critical methods like InitValues.Since there are so many value types that DataClass supports, it's irritating to write and maintain such code.
Given the fact that I don't own the source code of DataClass, I can't make any change to the DataClass. I wonder whether there is a way to refactor, so that I can deal with all the if statements of type check in one place?
Given that your are not allowed to change the DataClass, we need to make the consumers of the DataClass efficient. One way to do that would be to use Dictionaries to map the Types to the Actions/Methods. We would need to initialize these dictionaries only once. Here is an example to such a class.
class ConsumerClass // the one which uses DataClass objects
{
// All the Mappings required by this consumer class
readonly Dictionary<Type, Action<DataClass>> InitMap = new Dictionary<Type, Action<DataClass>>();
readonly Dictionary<Type, Action<DataClass>> DoSomethingAMap = new Dictionary<Type, Action<DataClass>>();
readonly Dictionary<Type, Action<DataClass>> DoSomethingBMap = new Dictionary<Type, Action<DataClass>>();
// Constructor
public ConsumerClass()
{
// Initialize all the mappings for all the required types for this consumer class here.
// This is a one time overhead, but will definitely speedup the methods within this class
// You could move this part further up the hierarchy of inheritance, to avoid repetitions in every other consumer class.
// For int
InitMap.Add(typeof(int), data => InitWith(data, -1));
DoSomethingAMap.Add(typeof(int), DoSomethingA<int>);
DoSomethingBMap.Add(typeof(int), DoSomethingB<int>);
// For double
InitMap.Add(typeof(double), data => InitWith(data, -9.99d));
DoSomethingAMap.Add(typeof(double), DoSomethingA<double>);
DoSomethingBMap.Add(typeof(double), DoSomethingB<double>);
// other types, if needed by this consumer
}
void InitValues(DataClass data)
{
// This takes care of your if s
InitMap[data.ValueType].Invoke(data);
}
void InitWith<T>(DataClass data, T defaultValue)
{
// much faster
var array = (T[])data.GetValues();
for (var i = 0; i < array.Length; i++)
array[i] = defaultValue;
}
void DoSomethingA(DataClass data)
{
DoSomethingAMap[data.ValueType].Invoke(data);
}
void DoSomethingA<T>(DataClass data)
{
var array = (T[])data.GetValues();
// do something
}
void DoSomethingB(DataClass data)
{
DoSomethingBMap[data.ValueType].Invoke(data);
}
void DoSomethingB<T>(DataClass data)
{
var array = (T[])data.GetValues();
// do something
}
}
There is some redundant code in the constructor, so there could still be a better way to write this mechanism. But you should get an idea of how you could clean up your ifs and still improve the performance.

How do I make a dynamic .Net object enumerable from IronRuby?

I have an application that implements several objects in C# and then expects those objects to be usable from IronRuby by adding them to a Microsoft.Scripting.Hosting.ScriptScope. This works for the most part: I've learned how to implement the various members of DynamicObject to make things act correctly. But how do I make an object compatible with Ruby's for loops?
My C# object looks like this:
public class TrialObject : DynamicObject, IEnumerable<int> {
public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result) {
if (indexes.Length != 1) return base.TryGetIndex(binder, indexes, out result);
try {
var index = (int)indexes[0];
result = index;
return true;
} catch { return base.TryGetIndex(binder, indexes, out result); }
}
public int Length { get { return 3; } }
public IEnumerator<int> GetEnumerator() {
yield return 0;
yield return 1;
yield return 2;
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
Then I try to use the object from ruby, like so.
trial.Length # returns 3
trial[0] # returns 0
trial[2] # returns 2
for t in trial do <stuff>; end #error: no block given
How do I adjust the trial object to allow it to work in a for loop? I know I could use "i in 0..trial.Length-1" as a hack around, but I'd rather fix the problem than introduce a hack.
After some trial and error, I learned that I could get the desired effect by adding an "each" method to my class.
public class TrialObject : DynamicObject, IEnumerable<int> {
...
public IEnumerable<BuildableObject> each() { return this; }
...
}
It seems as if ironruby uses the "each" method to implement its for. So by adding an each method, I can get this dynamic object to act like the IEnumerable it's trying to be.

ASP.NET MVC/C# - Type casting to an array in a custom required validation attribute

I'm attempting to create a custom required validation attribute which will be able to take in a 1d array of any size and verify that at least one element is not null/empty string. I'm having some trouble figuring out how to turn the incoming generic object into an array. Here's what I have so far:
public class RequiredArrayAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
var valueType = value.GetType();
if (!valueType.IsArray)
{
return false;
}
bool hasValue = false;
foreach (var item in value)
{
/* if (item != null/empty)
* {
* hasValue = true;
* }
*/
}
return hasValue;
}
}
While my specific use case in this instance will be dealing with string[], I'd like to keep the attribute as generic as possible for future use in other projects. Any ideas on how to proceed?
EDIT:
I basically need to do something like:
foreach (var item in (valueType[])value)
{
// ...
}
But I'm not sure how/if it's possible to dynamically cast to an array like that.
i believe you need following:
generic handeling of your loop: check answer below
C# Syntax - Example of a Lambda Expression - ForEach() over Generic List
Cast as T:
you can create separate class that will represent T
eg:
public class Foo{
public string Boo{get;set;}
}
and after you put it into List list = new List() etc:)

How to detect if a property exists on an ExpandoObject?

In javascript you can detect if a property is defined by using the undefined keyword:
if( typeof data.myProperty == "undefined" ) ...
How would you do this in C# using the dynamic keyword with an ExpandoObject and without throwing an exception?
According to MSDN the declaration shows it is implementing IDictionary:
public sealed class ExpandoObject : IDynamicMetaObjectProvider,
IDictionary<string, Object>, ICollection<KeyValuePair<string, Object>>,
IEnumerable<KeyValuePair<string, Object>>, IEnumerable, INotifyPropertyChanged
You can use this to see if a member is defined:
var expandoObject = ...;
if(((IDictionary<String, object>)expandoObject).ContainsKey("SomeMember")) {
// expandoObject.SomeMember exists.
}
An important distinction needs to be made here.
Most of the answers here are specific to the ExpandoObject which is mentioned in the question. But a common usage (and reason to land on this question when searching) is when using the ASP.Net MVC ViewBag. That's a custom implementation/subclass of DynamicObject, which won't throw an Exception when you check any arbitrary property name for null. Suppose you might declare a property like:
#{
ViewBag.EnableThinger = true;
}
Then suppose you wanted to check its value, and whether it's even set - whether it exists. The following is valid, will compile, won't throw any exceptions, and gives you the right answer:
if (ViewBag.EnableThinger != null && ViewBag.EnableThinger)
{
// Do some stuff when EnableThinger is true
}
Now get rid of the declaration of EnableThinger. Same code compiles and runs properly. No need for reflection.
Unlike ViewBag, ExpandoObject will throw if you check for null on a property that doesn't exist. In order to get MVC ViewBag's gentler functionality out of your dynamic objects, you'll need to use an implementation of dynamic that doesn't throw.
You could simply use the exact implementation in MVC ViewBag:
. . .
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = ViewData[binder.Name];
// since ViewDataDictionary always returns a result even if the key does not exist, always return true
return true;
}
. . .
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/DynamicViewDataDictionary.cs
You can see it being tied into MVC Views here, in MVC ViewPage:
http://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/ViewPage.cs
The key to DynamicViewDataDictionary's graceful behavior is the Dictionary implementation on ViewDataDictionary, here:
public object this[string key]
{
get
{
object value;
_innerDictionary.TryGetValue(key, out value);
return value;
}
set { _innerDictionary[key] = value; }
}
https://github.com/ASP-NET-MVC/aspnetwebstack/blob/master/src/System.Web.Mvc/ViewDataDictionary.cs
In other words, it always returns a value for all keys, regardless of what's in it - it simply returns null when nothing's there. But, ViewDataDictionary has the burden of being tied to MVC's Model, so it's better to strip out just the graceful dictionary parts for use outside MVC Views.
It's too long to really post all the guts here - most of it just implementing IDictionary - but here's a dynamic object (class DDict) that doesn't throw for null checks on properties that haven't been declared, on Github:
https://github.com/b9chris/GracefulDynamicDictionary
If you just want to add it to your project via NuGet, its name is GracefulDynamicDictionary.
I wanted to create an extension method so I could do something like:
dynamic myDynamicObject;
myDynamicObject.propertyName = "value";
if (myDynamicObject.HasProperty("propertyName"))
{
//...
}
... but you can't create extensions on ExpandoObject according to the C# 5 documentation (more info here).
So I ended up creating a class helper:
public static class ExpandoObjectHelper
{
public static bool HasProperty(ExpandoObject obj, string propertyName)
{
return obj != null && ((IDictionary<String, object>)obj).ContainsKey(propertyName);
}
}
To use it:
// If the 'MyProperty' property exists...
if (ExpandoObjectHelper.HasProperty(obj, "MyProperty"))
{
...
}
UPDATED: You can use delegates and try to get a value from the dynamic object property if it exists. If there is no property, simply catch the exception and return false.
Take a look, it works fine for me:
class Program
{
static void Main(string[] args)
{
dynamic userDynamic = new JsonUser();
Console.WriteLine(IsPropertyExist(() => userDynamic.first_name));
Console.WriteLine(IsPropertyExist(() => userDynamic.address));
Console.WriteLine(IsPropertyExist(() => userDynamic.last_name));
}
class JsonUser
{
public string first_name { get; set; }
public string address
{
get
{
throw new InvalidOperationException("Cannot read property value");
}
}
}
static bool IsPropertyExist(GetValueDelegate getValueMethod)
{
try
{
//we're not interesting in the return value. What we need to know is whether an exception occurred or not
getValueMethod();
return true;
}
catch (RuntimeBinderException)
{
// RuntimeBinderException occurred during accessing the property
// and it means there is no such property
return false;
}
catch
{
//property exists, but an exception occurred during getting of a value
return true;
}
}
delegate string GetValueDelegate();
}
The output of the code is the following:
True
True
False
I answered a very similar question recently: How do I reflect over the members of dynamic object?
Shortly, ExpandoObject is not the only dynamic object you might get. Reflection would work for static types (types that do not implement IDynamicMetaObjectProvider). For types that do implement this interface, reflection is basically useless. For ExpandoObject, you can simply check whether the property is defined as a key in the underlying dictionary. For other implementations, it might be challenging and sometimes the only way is to work with exceptions. For details, follow the link above.
Why you do not want to use Reflection to get set of type properyes? Like this
dynamic v = new Foo();
Type t = v.GetType();
System.Reflection.PropertyInfo[] pInfo = t.GetProperties();
if (Array.Find<System.Reflection.PropertyInfo>(pInfo, p => { return p.Name == "PropName"; }). GetValue(v, null) != null))
{
//PropName initialized
}
This extension method checks for the existence of a property and then returns the value or null. This is useful if you do not want your applications to throw unnecessary exceptions, at least ones you can help.
public static object Value(this ExpandoObject expando, string name)
{
var expandoDic = (IDictionary<string, object>)expando;
return expandoDic.ContainsKey(name) ? expandoDic[name] : null;
}
If can be used as such :
// lookup is type 'ExpandoObject'
object value = lookup.Value("MyProperty");
or if your local variable is 'dynamic' you will have to cast it to ExpandoObject first.
// lookup is type 'dynamic'
object value = ((ExpandoObject)lookup).Value("PropertyBeingTested");
Depending on your use case, if null can be considered as being the same as undefined, you can turn your ExpandoObject into a DynamicJsonObject.
dynamic x = new System.Web.Helpers.DynamicJsonObject(new ExpandoObject());
x.a = 1;
x.b = 2.50;
Console.WriteLine("a is " + (x.a ?? "undefined"));
Console.WriteLine("b is " + (x.b ?? "undefined"));
Console.WriteLine("c is " + (x.c ?? "undefined"));
Output:
a is 1
b is 2.5
c is undefined
(authorDynamic as ExpandoObject).Any(pair => pair.Key == "YourProp");
Hey guys stop using Reflection for everything it costs a lots of CPU cycles.
Here is the solution:
public class DynamicDictionary : DynamicObject
{
Dictionary<string, object> dictionary = new Dictionary<string, object>();
public int Count
{
get
{
return dictionary.Count;
}
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
string name = binder.Name;
if (!dictionary.TryGetValue(binder.Name, out result))
result = "undefined";
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
dictionary[binder.Name] = value;
return true;
}
}
Try this one
public bool PropertyExist(object obj, string propertyName)
{
return obj.GetType().GetProperty(propertyName) != null;
}

Categories