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.
Related
I've read Eric's article here about foreach enumeration and about the different scenarios where foreach can work
In order to prevent the old C# version to do boxing , the C# team enabled duck typing for foreach to run on a non- Ienumerable collection.(A public GetEnumerator that return something that has public MoveNext and Current property is sufficient(.
So , Eric wrote a sample :
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
object IEnumerator.Current { return this.Current; }
int Current { return index * index; }
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
But I believe it has some typos (missing get accessor at Current property implementation) which prevent it from compiling (I've already Emailed him).
Anyway here is a working version :
class MyIntegers : IEnumerable
{
public class MyEnumerator : IEnumerator
{
private int index = 0;
public void Reset()
{
throw new NotImplementedException();
}
object IEnumerator.Current {
get { return this.Current; }
}
int Current {
get { return index*index; }
}
public bool MoveNext()
{
if (index > 10) return false;
++index;
return true;
}
}
public MyEnumerator GetEnumerator() { return new MyEnumerator(); }
IEnumerator IEnumerable.GetEnumerator() { return this.GetEnumerator(); }
}
Ok.
According to MSDN :
A type C is said to be a collection type if it implements the
System.Collections.IEnumerable interface or implements the
collection pattern by meeting all of the following criteria:
C contains a public instance method with the signature GetEnumerator() that returns a struct-type, class-type, or interface-type, which is called E in the following text.
E contains a public instance method with the signature MoveNext() and the return type bool.
E contains a public instance property named Current that permits reading the current value. The type of this property is said to be the element type of the collection type.
OK. Let's match the docs to Eric's sample
Eric's sample is said to be a collection type because it does implements the System.Collections.IEnumerable interface ( explicitly though). But it is not(!) a collection pattern because of bullet 3 : MyEnumerator does not public instance property named Current.
MSDN says :
If the collection expression is of a type that implements the
collection pattern (as defined above), the expansion of the foreach
statement is:
E enumerator = (collection).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Otherwise , The collection expression is of a type that implements
System.IEnumerable (!), and the expansion of the foreach statement is:
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
ElementType element = (ElementType)enumerator.Current;
statement;
}
}
finally {
IDisposable disposable = enumerator as System.IDisposable;
if (disposable != null) disposable.Dispose();
}
Question #1
It seems that Eric's sample neither implements the
collection pattern nor System.IEnumerable - so it's not supposed to match any of the condition specified above. So how come I can still iterate it via :
foreach (var element in (new MyIntegers() as IEnumerable ))
{
Console.WriteLine(element);
}
Question #2
Why do I have to mention new MyIntegers() as IEnumerable ? it's already Ienumerable (!!) and even after that , Isn't the compiler is already doing the job by itself via casting :
((System.Collections.IEnumerable)(collection)).GetEnumerator() ?
It is right here :
IEnumerator enumerator =
((System.Collections.IEnumerable)(collection)).GetEnumerator();
try {
while (enumerator.MoveNext()) {
...
So why it still wants me to mention as Ienumerable ?
MyEnumerator does not has the required public methods
Yes it does - or rather, it would if Current were public. All that's required is that it has:
A public, readable Current property
A public MoveNext() method with no type arguments returning bool
The lack of public here was just another typo, basically. As it is, the example doesn't do what it's meant to (prevent boxing). It's using the IEnumerable implementation because you're using new MyIntegers() as IEnumerable - so the expression type is IEnumerable, and it just uses the interface throughout.
You claim that it doesn't implement IEnumerable, (which is System.Collections.IEnumerable, btw) but it does, using explicit interface implementation.
It's easiest to test this sort of thing without implementing IEnumerable at all:
using System;
class BizarreCollection
{
public Enumerator GetEnumerator()
{
return new Enumerator();
}
public class Enumerator
{
private int index = 0;
public bool MoveNext()
{
if (index == 10)
{
return false;
}
index++;
return true;
}
public int Current { get { return index; } }
}
}
class Test
{
static void Main(string[] args)
{
foreach (var item in new BizarreCollection())
{
Console.WriteLine(item);
}
}
}
Now if you make Current private, it won't compile.
The reference to System.IEnumerable on the MSDN is nothing more than a typo in an old language specification, no such interface exists, I believe it should be referring to System.Collections.IEnumerable.
You should really read the language specification of the version of C# you are using, the C# 5.0 language specification is available here.
Some further information about why failing to cast this example results in an error rather than falling back to using System.Collections.IEnumerable:
In the specification for foreach (section 8.8.4) you will see the rules have slightly changed (some steps have been cut for brevity):
Perform member lookup on the type X with identifier GetEnumerator and no type arguments. If the member lookup does not produce a match, or it produces an ambiguity, or produces a match that is not a method group, check for an enumerable interface as described below. It is recommended that a warning be issued if member lookup produces anything except a method group or no match.
Perform overload resolution using the resulting method group and an empty argument list. If overload resolution results in no applicable methods, results in an ambiguity, or results in a single best method but that method is either static or not public, check for an enumerable interface as described below. It is recommended that a warning be issued if overload resolution produces anything except an unambiguous public instance method or no applicable methods.
If the return type E of the GetEnumerator method is not a class, struct or interface type, an error is produced and no further steps are taken.
Member lookup is performed on E with the identifier Current and no type arguments. If the member lookup produces no match, the result is an error, or the result is anything except a public instance property that permits reading, an error is produced and no further steps are taken.
The collection type is X, the enumerator type is E, and the element type is the type of the Current property.
So from the first bullet point we would find the public MyEnumerator GetEnumerator(), the second and third bullets go through without error. When we get to the fourth bullet point, no public member called Current is available which results in the error you are seeing without the cast, this exact situation never gives the compiler the opportunity to look for the enumerable interface.
When you explicitly cast your instance to an IEnumerable all of the requirements are satisfied as the type IEnumerable and the associated IEnumerator satisfy all of the requirements.
Also from the documentation:
The above steps, if successful, unambiguously produce a collection type C, enumerator type E and element type T. A foreach statement of the form
foreach (V v in x) embedded-statement
is then expanded to:
{
E e = ((C)(x)).GetEnumerator();
try {
while (e.MoveNext()) {
V v = (V)(T)e.Current;
embedded-statement
}
}
finally {
… // Dispose e
}
}
So given your explicit cast to IEnumerable, you will end up with the following:
C = System.Collections.IEnumerable
x = new MyIntegers() as System.Collections.IEnumerable
E = System.Collections.IEnumerator
T = System.Object
V = System.Object
{
System.Collections.IEnumerator e = ((System.Collections.IEnumerable)(new MyIntegers() as System.Collections.IEnumerable)).GetEnumerator();
try {
while (e.MoveNext()) {
System.Object element = (System.Object)(System.Object)e.Current;
Console.WriteLine(element);
}
}
finally {
System.IDisposable d = e as System.IDisposable;
if (d != null) d.Dispose();
}
}
Which explains why using the cast works.
In practice this seems simple but I'm getting really confused about it. Java's enumeration hasMoreElements() and nextElement() methods are related but work differently from C#'s IEnumerator MoveNext() and Current() properties of course. But how would I translate something like this?:
//class declaration, fields constructors, unrelated code etc.
private Vector atomlist = new Vector();
public int getNumberBasis() {
Enumeration basis = this.getBasisEnumeration();
int numberBasis = 0;
while (basis.hasMoreElements()) {
Object temp = basis.nextElement();
numberBasis++;
}
return numberBasis;
}
public Enumeration getBasisEnumeration() {
return new BasisEnumeration(this);
}
private class BasisEnumeration implements Enumeration {
Enumeration atoms;
Enumeration basis;
public BasisEnumeration(Molecule molecule) {
atoms = molecule.getAtomEnumeration();
basis = ((Atom) atoms.nextElement()).getBasisEnumeration();
}
public boolean hasMoreElements() {
return (atoms.hasMoreElements() || basis.hasMoreElements());
}
public Object nextElement() {
if (basis.hasMoreElements())
return basis.nextElement();
else {
basis = ((Atom) atoms.nextElement()).getBasisEnumeration();
return basis.nextElement();
}
}
}
As you can see, the enumration class's methods are overloaded and I don't think replacing hasMoreElements and nextElement with MoveNext and Current everywhere would work... because the basis.nextElement() calls hasMoreElements() again in an if-else statement. If I was to replace hasMoreElements with MoveNext(), the code would advance twice instead of one.
You can indeed implement IEnumerable yourself, but it generally needed only for exercises in internals of C#. You'd probably use either iterator method:
IEnumerable<Atom> GetAtoms()
{
foreach(Atom item in basis)
{
yield return item;
}
foreach(Atom item in atoms)
{
yield return item;
}
}
Or Enumerable.Concat
IEnumerable<Atom> GetAtoms()
{
return basis.Concat(atoms);
}
Say I have a list of objects called components:
List<object> components = new List<object>();
Say it's populated with objects of the classes engine, wheel, frame. Now, I want to make a function that takes a class as a parameter and returns true if the list has an object of that class. Like this:
public static bool HasComponent( *the class* ) {
foreach(object c in components) {
if(c is *the class*)
return true;
}
return false;
}
How do i go about doing that? is it possible?
use linq:
components.OfType<YouType>().Any();
Use generics:
public static bool HasComponent<T>() {
foreach(object c in components) {
if(c is T)
return true;
}
return false;
}
Call it:
Obj.HasComponent<Wheel>();
You can call GetType() to get the type of any object in .Net or use the is keyword. Indeed, you could do this on the list using LINQ with something like:
components.Any(x => x is Wheel);
and substitute Wheel for the desired type.
Something more like this
public static bool HasComponent<TheType>()
{
foreach(object c in components)
{
if(c is TheType)
{
return true;
}
}
return false;
}
Or shorter
public static bool HasComponent<TheType>()
{
return components.OfType<TheType>().Count() > 0;
}
Call it with
HasComponent<TheType>()
I know some answers suggested using the "is" keyword, but you'll want to be careful in inheritance situations. e.g. If Cow derives from Animal, then HasComponent<Cow>() will return true for both. You should really compare types to avoid the problem:
public static bool HasComponent<T>()
{
return components.Any(i => i.GetType() == typeof(T));
}
Of course, you can do it without generics by passing in a type, but generics is really the way to go:
public static bool HasComponent(Type type)
{
return components.Any(i => i.GetType() == type);
}
If you are working with a multiple-threaded application, you should be sure that the object is in the list at the time you search for it. Because the other thread can remove this object at the same time as the search. So, a NullReferenceException could be thrown. In order to avoid this situation, you can use this function.
public static bool HasComponent<T>()
{
foreach (object c in components)
{
lock (c.GetType())
{
if (c is T)
{
return true;
}
}
}
return false;
}
But, to call this function your list should be static.
To find this out, we should use an extended for loop that is 'foreach', which traverses through all types of class objects and checks the desired object of specific class and returns either true or false.
public static bool HasComponent<Type>() {
foreach(object c in l) {
if(object c in Type)
return true;
}
return false;
}
What is the concrete type for this IEnumerable<string>?
private IEnumerable<string> GetIEnumerable()
{
yield return "a";
yield return "a";
yield return "a";
}
It's a compiler-generated type. The compiler generates an IEnumerator<string> implementation that returns three "a" values and an IEnumerable<string> skeleton class that provides one of these in its GetEnumerator method.
The generated code looks something like this*:
// No idea what the naming convention for the generated class is --
// this is really just a shot in the dark.
class GetIEnumerable_Enumerator : IEnumerator<string>
{
int _state;
string _current;
public bool MoveNext()
{
switch (_state++)
{
case 0:
_current = "a";
break;
case 1:
_current = "a";
break;
case 2:
_current = "a";
break;
default:
return false;
}
return true;
}
public string Current
{
get { return _current; }
}
object IEnumerator.Current
{
get { return Current; }
}
void IEnumerator.Reset()
{
// not sure about this one -- never really tried it...
// I'll just guess
_state = 0;
_current = null;
}
}
class GetIEnumerable_Enumerable : IEnumerable<string>
{
public IEnumerator<string> GetEnumerator()
{
return new GetIEnumerable_Enumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
Or maybe, as SLaks says in his answer, the two implementations end up in the same class. I wrote this based on my choppy memory of generated code I'd looked at before; really, one class would suffice, as there's no reason the above functionality requires two.
In fact, come to think of it, the two implementations really should fall within a single class, as I just remembered the functions that use yield statements must have a return type of either IEnumerable<T> or IEnumerator<T>.
Anyway, I'll let you perform the code corrections to what I posted mentally.
*This is purely for illustration purposes; I make no claim as to its real accuracy. It's only to demonstrate in a general way how the compiler does what it does, based on the evidence I've seen in my own investigations.
The compiler will automatically generate a class that implements both IEnumerable<T> and IEnumerator<T> (in the same class).
Jon Skeet has a detailed explanation.
The concrete implementation of IEnumerable<string> returned by the method is an anonymous type generated by the compiler
Console.WriteLine(GetIEnumerable().GetType());
Prints :
YourClass+<GetIEnumerable>d__0
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();
}
}