Last active
October 16, 2022 22:42
-
-
Save shanecelis/ee16908f7c00ce4a7aeb55c4bf3477fc to your computer and use it in GitHub Desktop.
"Use stackoverflow.com code? Yes. Ever cite it? Usually I just add a link but here it is formally. #programming"—@shanecelis
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Original code Copyright (c) 2011 cdiggins[1] | |
Modified code Copyright (c) 2016 Shane Celis, @shanecelis[2] | |
Licensed under the CC-BY-SA 3.0[3] | |
Original code posted to this question[4] and answer[5] from | |
stackoverflow.com where user contributions are licensed under | |
CC-BY-SA 3.0 with attribution required. | |
[1]: https://stackoverflow.com/users/184528/cdiggins | |
[2]: https://twitter.com/shanecelis | |
[3]: http://creativecommons.org/licenses/by-sa/3.0/ | |
[4]: http://stackoverflow.com/questions/3151702/discriminated-union-in-c-sharp | |
[5]: http://stackoverflow.com/a/7302957/6454690 | |
*/ | |
/* | |
CHANGES | |
------- | |
May 21, 2016 | |
[ENHANCEMENTS] | |
* Removed 'dynamic' keyword and made other small changes to support | |
Unity. (Could be considered a degradation rather than an | |
enhancement.) | |
[BUG FIXES] | |
* Now works with non-static delegates. | |
* Throws exception on `Match<void>` to stop Unity Editor from crashing. | |
*/ | |
using System; | |
using UnityEngine.Assertions; | |
public class UnionBase<A> | |
{ | |
object value; | |
public UnionBase(A a) { value = a; } | |
protected UnionBase(object x) { value = x; } | |
protected T InternalMatch<T>(params Delegate[] ds) | |
{ | |
var vt = value.GetType(); | |
foreach (var d in ds) | |
{ | |
var mi = d.Method; | |
// These are always true if InternalMatch is used correctly. | |
Assert.IsTrue(mi.GetParameters().Length == 1); | |
Assert.IsTrue(typeof(T).IsAssignableFrom(mi.ReturnType)); | |
//UnityEngine.Debug.Log("declaring type " + mi.DeclaringType); | |
var pt = mi.GetParameters()[0].ParameterType; | |
if (pt.IsAssignableFrom(vt)) { | |
if (typeof(T) != typeof(void)) { | |
/* If it's not static, we need to use the delegate's target. -sec */ | |
return (T) mi.Invoke(d.Target, new object[] { value }); | |
} else { | |
throw new Exception("Cannot return void; consider using object."); | |
} | |
} | |
} | |
throw new Exception("No appropriate matching function was provided"); | |
} | |
public T Match<T>(Func<A, T> fa) { return InternalMatch<T>(fa); } | |
} | |
public class Union<A, B> : UnionBase<A> | |
{ | |
public Union(A a) : base(a) { } | |
public Union(B b) : base(b) { } | |
protected Union(object x) : base(x) { } | |
public T Match<T>(Func<A, T> fa, Func<B, T> fb) { return InternalMatch<T>(fa, fb); } | |
} | |
public class Union<A, B, C> : Union<A, B> | |
{ | |
public Union(A a) : base(a) { } | |
public Union(B b) : base(b) { } | |
public Union(C c) : base(c) { } | |
protected Union(object x) : base(x) { } | |
public T Match<T>(Func<A, T> fa, Func<B, T> fb, Func<C, T> fc) { return InternalMatch<T>(fa, fb, fc); } | |
} | |
public class Union<A, B, C, D> : Union<A, B, C> | |
{ | |
public Union(A a) : base(a) { } | |
public Union(B b) : base(b) { } | |
public Union(C c) : base(c) { } | |
public Union(D d) : base(d) { } | |
protected Union(object x) : base(x) { } | |
public T Match<T>(Func<A, T> fa, Func<B, T> fb, Func<C, T> fc, Func<D, T> fd) { return InternalMatch<T>(fa, fb, fc, fd); } | |
} | |
public class Union<A, B, C, D, E> : Union<A, B, C, D> | |
{ | |
public Union(A a) : base(a) { } | |
public Union(B b) : base(b) { } | |
public Union(C c) : base(c) { } | |
public Union(D d) : base(d) { } | |
public Union(E e) : base(e) { } | |
protected Union(object x) : base(x) { } | |
public T Match<T>(Func<A, T> fa, Func<B, T> fb, Func<C, T> fc, Func<D, T> fd, Func<E, T> fe) { return InternalMatch<T>(fa, fb, fc, fd, fe); } | |
} | |
// public class DiscriminatedUnionTest : IExample | |
// { | |
// public Union<int, bool, string, int[]> MakeUnion(int n) | |
// { | |
// return new Union<int, bool, string, int[]>(n); | |
// } | |
// public Union<int, bool, string, int[]> MakeUnion(bool b) | |
// { | |
// return new Union<int, bool, string, int[]>(b); | |
// } | |
// public Union<int, bool, string, int[]> MakeUnion(string s) | |
// { | |
// return new Union<int, bool, string, int[]>(s); | |
// } | |
// public Union<int, bool, string, int[]> MakeUnion(params int[] xs) | |
// { | |
// return new Union<int, bool, string, int[]>(xs); | |
// } | |
// public void Print(Union<int, bool, string, int[]> union) | |
// { | |
// var text = union.Match( | |
// n => "This is an int " + n.ToString(), | |
// b => "This is a boolean " + b.ToString(), | |
// s => "This is a string" + s, | |
// xs => "This is an array of ints " + String.Join(", ", xs)); | |
// Console.WriteLine(text); | |
// } | |
// public void Run() | |
// { | |
// Print(MakeUnion(1)); | |
// Print(MakeUnion(true)); | |
// Print(MakeUnion("forty-two")); | |
// Print(MakeUnion(0, 1, 1, 2, 3, 5, 8)); | |
// } | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment