I have an entity that can be in one of different states (StateA, StateB and StateC), and in each of them have relevant data of distinct types (TStateA, TStateB, TStateC). Enums in Rust represent this perfectly. What is the best way to implement something like this in C#?
This question may appear similar, but enums in Rust and unions in C are significantly different.
You need a class to represent your Entity
class Entity {States state;}
Then you need a set of classes to represent your states.
abstract class States {
// maybe something in common
}
class StateA : MyState {
// StateA's data and methods
}
class StateB : MyState {
// ...
}
Then you need to write code like
StateA maybeStateA = _state as StateA;
If (maybeStateA != null)
{
- do something with the data in maybeStateA
}
C# does not have a nice way of writing code for this yet, maybe the Pattern Matching that is being considered for C#.next would help.
I think you should rethink your design to use object relationships and containment, trying to take a design that works in rust and force it into C# may not be the best option.
This might be crazy, but if you are hard-up about emulating Rust-like enums in C#, you could do it with some generics. Bonus: you keep type-safety and also get Intellisense out of the deal! You'll lose a little flexibility with various value types, but I think the safety is probably worth the inconvenience.
enum Option
{
Some,
None
}
class RustyEnum<TType, TValue>
{
public TType EnumType { get; set; }
public TValue EnumValue { get; set; }
}
// This static class basically gives you type-inference when creating items. Sugar!
static class RustyEnum
{
// Will leave the value as a null `object`. Not sure if this is actually useful.
public static RustyEnum<TType, object> Create<TType>(TType e)
{
return new RustyEnum<TType, object>
{
EnumType = e,
EnumValue = null
};
}
// Will let you set the value also
public static RustyEnum<TType, TValue> Create<TType, TValue>(TType e, TValue v)
{
return new RustyEnum<TType, TValue>
{
EnumType = e,
EnumValue = v
};
}
}
void Main()
{
var hasSome = RustyEnum.Create(Option.Some, 42);
var hasNone = RustyEnum.Create(Option.None, 0);
UseTheEnum(hasSome);
UseTheEnum(hasNone);
}
void UseTheEnum(RustyEnum<Option, int> item)
{
switch (item.EnumType)
{
case Option.Some:
Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
break;
default:
Debug.WriteLine("You know nuffin', Jon Snow!");
break;
}
}
Here's another sample demonstrating the use of a custom reference type.
class MyComplexValue
{
public int A { get; set; }
public int B { get; set; }
public int C { get; set; }
public override string ToString()
{
return string.Format("A: {0}, B: {1}, C: {2}", A, B, C);
}
}
void Main()
{
var hasSome = RustyEnum.Create(Option.Some, new MyComplexValue { A = 1, B = 2, C = 3});
var hasNone = RustyEnum.Create(Option.None, null as MyComplexValue);
UseTheEnum(hasSome);
UseTheEnum(hasNone);
}
void UseTheEnum(RustyEnum<Option, MyComplexValue> item)
{
switch (item.EnumType)
{
case Option.Some:
Debug.WriteLine("Wow, the value is {0}!", item.EnumValue);
break;
default:
Debug.WriteLine("You know nuffin', Jon Snow!");
break;
}
}
This looks a lot like Abstract Data Types in functional languages. There's no direct support for this in C#, but you can use one abstract class for the data type plus one sealed class for each data constructor.
abstract class MyState {
// maybe something in common
}
sealed class StateA : MyState {
// StateA's data and methods
}
sealed class StateB : MyState {
// ...
}
Of course, there's nothing prohibiting you from adding a StateZ : MyState class later, and the compiler won't warn you that your functions are not exhaustive.
Just from the back of my head, as a quick implementation...
I would first declare the Enum type and define enumerate items normally.
enum MyEnum{
[MyType('MyCustomIntType')]
Item1,
[MyType('MyCustomOtherType')]
Item2,
}
Now I define the Attribute type MyTypeAttribute with a property called TypeString.
Next, I need to write an extension method to extract the Type for each enum item (first in string, then later reflect to real type):
public static string GetMyType(this Enum eValue){
var _nAttributes = eValue.GetType().GetField(eValue.ToString()).GetCustomAttributes(typeof (MyTypeAttribute), false);
// handle other stuff if necessary
return ((MyTypeAttribute) _nAttributes.First()).TypeString;
}
Finally, get the real type using reflection...
I think the upside of this approach is easy to use later in the code:
var item = MyEnum.SomeItem;
var itemType = GetType(item.GetMyType());
I've been looking into Rust recently and been thinking the same questions. The real problem is the absence of the Rust deconstruction pattern matching but the type itself is long-winded but relatively straightforward if you are willing to use boxing:
// You need a new type with a lot of boilerplate for every
// Rust-like enum but they can all be implemented as a struct
// containing an enum discriminator and an object value.
// The struct is small and can be passed by value
public struct RustyEnum
{
// discriminator type must be public so we can do a switch because there is no equivalent to Rust deconstructor
public enum DiscriminatorType
{
// The 0 value doesn't have to be None
// but it must be something that has a reasonable default value
// because this is a struct.
// If it has a struct type value then the access method
// must check for Value == null
None=0,
IVal,
SVal,
CVal,
}
// a discriminator for users to switch on
public DiscriminatorType Discriminator {get;private set;}
// Value is reference or box so no generics needed
private object Value;
// ctor is private so you can't create an invalid instance
private RustyEnum(DiscriminatorType type, object value)
{
Discriminator = type;
Value = value;
}
// union access methods one for each enum member with a value
public int GetIVal() { return (int)Value; }
public string GetSVal() { return (string)Value; }
public C GetCVal() { return (C)Value; }
// traditional enum members become static readonly instances
public static readonly RustyEnum None = new RustyEnum(DiscriminatorType.None,null);
// Rusty enum members that have values become static factory methods
public static RustyEnum FromIVal(int i)
{
return new RustyEnum(DiscriminatorType.IVal,i);
}
//....etc
}
Usage is then:
var x = RustyEnum::FromSVal("hello");
switch(x.Discriminator)
{
case RustyEnum::DiscriminatorType::None:
break;
case RustyEnum::DiscriminatorType::SVal:
string s = x.GetSVal();
break;
case RustyEnum::DiscriminatorType::IVal:
int i = x.GetIVal();
break;
}
If you add some extra public const fields this could be reduced to
var x = RustyEnum::FromSVal("hello");
switch(x.Discriminator)
{
case RustyEnum::None:
break;
case RustyEnum::SVal:
string s = x.GetSVal();
break;
case RustyEnum::IVal:
int i = x.GetIVal();
break;
}
... but you then need a different name for creating the valueless members (like None in this example)
It seems to me that if the C# compiler was to implement rust enums without changing the CLR then this is the sort of code that it would generate.
It would be easy enough to create a .ttinclude to generate this.
Deconstruction is not as nice as Rust match but there is no alternative that is both efficient and idiot proof (the inefficient way is to use something like
x.IfSVal(sval=> {....})
To summarize my rambling - It can be done but it's unlikely to be worth the effort.
Short answer you can't. Even if you feel you can just don't do it you would shoot yourself in foot in doing so. We'll have to wait for the C# team to come up with a type with something like below
struct lives on stack in most cases this means it has a fixed size in memory
What we are expecting is sort of multiple struct with different layout but still fits in one decided stack of memory. The way rust handles this is by using the memory size of largest of the group for example
# Right now:
struct A { int a } # 4 bytes
struct B { int a, int b } # 8 bytes
# Can do but highly don't recommend would be waste of precious time, memory and cpu
struct AB {
A a,
B b
} # 12 bytes + 2 bytes to keep bool to check which struct should be used in code
# Future/Should be
super struct AB {
A(int),
B(int, int)
} # 8 bytes
Never did anything in Rust, but looking at the docs it seams to me that you would have to implement a textbook C# class. Since Rust enums even support functions and implementations of various types.
Probabily an abstract class.
Related
I have been developing for windows mobile and android for sometime. And I'm confused about these two concepts.
Let's say I want to make decision based on some the user's device Screen Size. So I'll expect so predefined values. I could use a switch statement for handling my logic.
But I'm not sure whether I should use Enum of a Static Class for this purpose. Which one is a better approach.
I can do my logic in these two different ways. Which one is the correct approach? I'm confused. And is it possible for me to use String values also? Because currently I'm sticking with classes, I need to update to use all enums. So How about changing my Class to String Enum? Any way. Thanks.
Using Enum
//My predefined values
public enum ScreenSizeEnum
{
Small, Medium, Large, XLarge,
}
//Handling Logic
private void SetScreenSize(ScreenSizeEnum Screen)
{
switch (Screen)
{
case ScreenSizeEnum.Large:
//Do Logic
break;
case ScreenSizeEnum.Small:
//Do Logic
break;
}
}
Using Class
//My predefined values
public class ScreenSizeClass
{
public const int Small = 0;
public const int Medium = 1;
public const int Large = 2;
public const int XLarge = 3;
}
//Handling Logic
private void SetScreenSize(int Screen)
{
switch (Screen)
{
case ScreenSizeClass.Large:
//Do Logic
break;
case ScreenSizeClass.Small:
//Do Logic
break;
}
}
From Enumeration Types (C# Programming Guide):
An enumeration type (also named an enumeration or an enum) provides an
efficient way to define a set of named integral constants that may be
assigned to a variable.
The following are advantages of using an enum instead of a numeric
type:
You clearly specify for client code which values are valid for the variable.
In Visual Studio, IntelliSense lists the defined values.
So if you pass enum, it is strongly typed, so you automatically get control over what you can pass into a method.
ScreenSizeEnum screenSize = ScreenSizeEnum.Medium;
SetScreenSize(screenSize);
When using const or static fields you definitely need to check whether the passed int value is taken from the expected diapason.
int someScreenSizeValue = ...; //anything
SetScreenSize(someScreenSizeValue); //compiles
private void SetScreenSize(int screenSizeValue)
{
switch (screenSizeValue)
{
case ScreenSizeClass.Large:
//Do Logic
break;
case ScreenSizeClass.Small:
//Do Logic
break;
default:
// something else, what to do??
break;
}
}
Based on comments:
If it's necessary to check, whether some int is defined in enum, one can do something like this:
int somevallue = 0;
if(Enum.IsDefined(typeof(ScreenSizeEnum), somevallue))
{
//it's ok
}
Or an extension method:
public static T GetEnumValue<T>(this string value) where T : struct
{
Type t = typeof(T);
if (!t.IsEnum)
{
throw new Exception("T must be an enum");
}
else
{
T result;
if (Enum.TryParse<T>(value, out result))
return result;
return default(T);
}
}
which could be used
int someValue = 1;
ScreenSizeEnum screenSize = someValue.GetEnumValue<ScreenSizeEnum>();
As for the string (based on OP's edited question):
From enum (C# Reference):
The approved types for an enum are byte, sbyte, short, ushort, int,
uint, long, or ulong.
So you cannot have an enum of strings. But you can use names from enums, as ToString method returns the name, not the value of the enum.
ScreenSizeEnum.Small.ToString(); //Small
So you can have another extension method on strings:
public static T GetEnumValue<T>(this string value) where T : struct
{
Type t = typeof(T);
if (!t.IsEnum)
{
throw new Exception("T must be an enum");
}
else
{
if (Enum.IsDefined(t, value))
return (T)Enum.Parse(t, value);
return default(T);
}
}
So that
int intScreenSize = (int)ScreenSizeEnum.Small;
string strScreenSize = ScreenSizeEnum.Small.ToString();
ScreenSizeEnum intScreenSizeValue = intScreenSize.GetEnumValue<ScreenSizeEnum>(); //ScreenSizeEnum.Small
ScreenSizeEnum strScreenSizeValue = strScreenSize.GetEnumValue<ScreenSizeEnum>(); //ScreenSizeEnum.Small
This is precisely what enums are there for. Not that you can't use the static class with the constants, but enum is by far cleaner...
enums are basically used when you want a variable or parameter to have value from a fixed set of possible constants. You can replace enums with class with a set of static final int constants. But using enums is more flexible & readable appraoch over the later one.
A class can be very handy if you want more as the enumerator only. If you want to implement several Get... functions that can return other things that you need.
My example is that I have a class of some type but there is a related other type that I need to.
I'm using a library with (hundreds of, template-generated) classes without generic modifier, each extending the same classes with generic modifier (essentially to shorten the notation). E.g.
class DArr : NumberObject<double, MyArrayIndexer> { ... }
class IArr : NumberObject<int, MyArrayIndexer> { ... }
class DMat : NumberObject<double, MyMatrixIndexer> { ... }
class IMat : NumberObject<int, MyMatrixIndexer> { ... }
class BMat : NumberObject<bool, MyMatrixIndexer> { ... }
and so on
I now want to write functions that proccess these with a function that requires their internal type (e.g. internal copies that need to know whether we have 4 or 8 bytes per element, and what type of Indexer is being used). I therefore made the signature of my function:
public SomeUnrelatedClass<T> Process<T,TVal,T0>(SomeUnrelatedClass<T> obj) where T : NumberObject<TVal,T0> {
//here some tstuff that requires T, TVal and T0
}
but unfortunately it seems I can't use it in the way I need to, i.e.
SomeUnrelatedClass<DArr> input = ...;
SomeUnrelatedClass<DArr> output = Process(input);
since it fails to derive TVal and T0 from (why??), despite it being uniquely determined. How can I remedy this? Calling it as SomeUnrelatedClass<DArr> output = Process<DArr,double,MyArrayIndexer>(input); is not an option because in reality there's a lot more of these generics and they're a lot longer in name (and this function will be used thousands of times in future code, so I'd much rather now write a more complicated function that does it right and keeps the syntax simple). Ideally I'd not do a long list of "if type == ..." though, because the list of types is template-generated and changes over time as types get added (meaning this template would be dependent on the other template, etc.)
I've thought of silly hacks like making the syntax Process<T,TVal,T0>(SomeUnrelatedClass<T> obj,SomeUnrelatedClass<NumberObject<TVal,T0>> sameObj) and calling SomeUnrelatedClass<DArr> output = Process(input,input); but I feel like that's just a really poor fix. What's a more 'proper' way to do this?
I think you might be in some luck here, because C# does not infer types based on the constraints that you specify. I think it's part of the specification, from what I could dig out. But you might be able to solve you problem anyway :) - I managed to get the following running.
{
var input = new DArr(12.34);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
{
var input = new IArr(42);
var output = Visitor.Process(input);
Console.WriteLine($"Type [{output.Obj.GetType()}] with value {output.Obj.MyType}");
}
// Generated output:
//
// Type [DArr] with value 12,34
// Type [IArr] with value 42
So no matter how many types you define that Process method will consume and map the input to the right concrete type.
Below is how this could work:
public class NumberObject<TType, TIndexer>
{
public NumberObject(TType type) { MyType = type; }
public TType MyType { get; }
}
public class MyArrayIndexer { }
public class DArr : NumberObject<double, MyArrayIndexer>
{
public DArr(double value) : base(value) { }
}
public class IArr : NumberObject<int, MyArrayIndexer>
{
public IArr(int value) : base(value) { }
}
public class SomeUnrelatedClass<T>
{
public T Obj { get; }
public SomeUnrelatedClass(T obj){ Obj = obj; }
}
public class Visitor
{
public static SomeUnrelatedClass<NumberObject<TVal, T0>> Process<TVal, T0>(NumberObject<TVal, T0> input)
{
return new SomeUnrelatedClass<NumberObject<TVal, T0>>(input);
}
}
The trick here is to reduce the number of generic parameters - getting rid of the T type as it can directly be expressed by the remaining two as you actually also write yourself
T is NumberObject<TVal, T0>
When the level of types to infer is reduced the C# compiler can determine them directly and viola you can leave you specifying generic parameters to the Process method.
I'm currently refactoring a large codebase and converting it from vb.net to c#. One of the functions does some funky logic around loading columns from a datasource and putting them into properties.
With vb, the creator didn't need to worry about conversions etc. but with c# I need to consider it.
So, given a piece of code like the below, I need to convert an int to the relevant enum type.
public class SomeType
{
public SomeEnum enumValue { get; set; }
public void SetValues()
{
... GetValuesFromDataSource
... Iterates values
enumValue = SetProperty(enumValue, valueFromDataSource);
}
}
protected dynamic SetProperty(object oProperty, object oValue)
{
if (oProperty is Enum)
{
... Convert oValue to the relevant enum type and assign to oProperty
}
}
Just to add some clarity. The references to SetProperty number in the thousands, so I don't want to refactor by hand.
The oValue will come in as an int. There is other logic in the SetProperty method for other types. oProperty could be one of any of the hundreds of enums in the application.
If valueFromDataSource is an object and is just the boxed enum in question, you can use something like the following
if (valueFromDataSource is someEnum)
{
return (someEnum)valueFromDataSource
}
else if (valueFromDataSource is someOtherEnum)
{
return (someOtherEnum)valueFromDataSource
}
However in your original function you're returning back an object, which will box it again, nothing gained
Which leads me to believe your valueFromDataSource is actually an int, therefore, there is no way back, and you would at best have to guess what the enum should be
In a design scenario, your best bet is not store the enum as an int, and just box it
Second would be to leave a hint to the enum type or something
Update
can you convert an int to an Enum without knowing the type at design time?
Unfortunately the answer is no, in VB or C# or any other language, it just cant be done
If your re-factoring code, you must have some wires crossed as the VB creator couldn't do this either
Update to do it more dynamically, using an out parameter for a SetProperty Method
class Program
{
static void Main(string[] args)
{
Entity tt = default(Entity);
Test tester = default(Test);
tester = SetProperty(tester, 5);
tt = SetProperty(tt, "Test7");
Console.WriteLine(tester);
Console.WriteLine(tt);
Console.ReadLine();
}
public static T Cast<T>(T target, object Source)
{
return (T)Source;
}
public static dynamic SetProperty<T>(T target, object source)
{
Type t = typeof(T);
Type sourceType = source.GetType();
if (t.IsEnum)
{
Type enumType = t.GetEnumUnderlyingType();
if (Type.Equals(sourceType, enumType))
{
return (T)Cast(Activator.CreateInstance(enumType), source);
}
if (Type.Equals(sourceType, typeof(string)))
{
Array names = t.GetEnumValues();
foreach (var name in names)
{
if (name.ToString() == source.ToString())
{
return (T)name;
}
}
}
return default(T);
}
return null;
}
public enum Entity
{
Test5,
Test7,
Test8
}
public enum Test : int
{
Test1 = 1,
Test2 = 5,
Test4 = 7
}
}
the output would then be:
Test2
Test7
I have an array of structs, where the struct has three integer fields. It is sorted by one of the fields, say F, and I want a way to do a binary search with respect to this field, that is, a function of the form binarySearch(mystruct[] myarray, int val) which returns the index of the structure in which field F = val. I know that there is an existing Array.BinarySearch(T[] array, T value) function, but it only allows to search for a type T that is the same as the types in the array. This means that if I want to search with respect to a value, I need to create a new struct and set field F to that value just so that I can pass it to this function. I don't think there would be significant performance overhead but it seems ugly. The other way I can think is to implement the function myself, but this also seems inelegant when something so similar exists. Any suggestions for a better way or which way would be preferred?
You can either implement IComparable<T> for your struct to compare on the field (F), or you can create an IComparer<> for your struct that will compare based on that field and pass that into Array.BinarySearch().
So either:
// using IComparable<T>
public struct MyStruct : IComparable<MyStruct>
{
public int F { get; set; }
// other fields that should not affect "search"
public int X { get; set; }
public int CompareTo(MyStruct other)
{
return F.CompareTo(other.F);
}
}
Which can be called as:
MyStruct target = new MyStruct { F = 13 };
Array.BinarySearch(arrayOfMyStruct, target);
Or a separate IComparer<MyStruct>:
public struct MyStruct
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
}
public struct MyStructComparer : IComparer<MyStruct>
{
public int Compare(MyStruct x, MyStruct y)
{
return x.F.CompareTo(y.F);
}
}
Which can be called like:
MyStruct target { F = 13; }
Array.BinarySearch(myArrayOfStruct, target, new MyStructComparer());
The first has less code, but it strongly couples ordering to the type, which if you want to alter ordering based on situation (that is, allow multiple sort orders), this isn't ideal. The latter gives more flexibility in that you can provide multiple different orders independent of the struct, but it does require an extra class.
UPDATE
If you don't want to create a dummy struct to compare against, you can implement IComparable like:
public struct MyStruct : IComparable
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
public int CompareTo(object other)
{
// if the type is NOT an int, you can decide whether you'd prefer
// to throw, but the concept of comparing the struct to something
// unknown shouldn't return a value, should probably throw.
return F.CompareTo((int)other);
}
}
Which could be called like:
Array.BinarySearch(arrayOfMyStruct, 13);
But again, this strongly ties your implementation of the class to a given comparison type, which I think is uglier than using a dummy search target, but that's my personal preference. Personally, especially with initializer syntax being as short as it is, I prefer to use the dummy target:
var target = new MyStruct { F = 13 };
UPDATE: You can support both int and MyStruct comparissons, but it gets messy quickly, which is why I personally, again, recommend using the dummy struct to avoid the headaches:
// implement IComparable<int> for the int search (w/o dummy), and IComparable<MyStruct> for sort
public struct MyStruct : IComparable, IComparable<MyStruct>, IComparable<int>
{
public int F { get; set; }
// other non-sort/search affecting properties
public int X { get; set; }
public int CompareTo(object other)
{
if (other is int)
return F.CompareTo((int)other);
if (other is MyStruct)
return F.CompareTo((MyStruct)other);
throw new InvalidOperationException("Other must be int or MyStruct.");
}
public int CompareTo(MyStruct other)
{
return F.CompareTo(other.F);
}
public int CompareTo(int other)
{
return F.CompareTo(other);
}
}
If your struct implements IComparable, you can use:
// myValue is an the value of the field to compare to
Array.BinarySearch(myArray, myValue);
as described in http://msdn.microsoft.com/en-us/library/y15ef976.aspx
You can compare a struct to an object with IComparable, so you can pass in the value intead of a new struct. In your implementation of CompareTo, you can compare any value with the field value, allowing you to say 'My struct should be considered greater/less than this number'.
EDIT:
Here is an example of CompareTo for your struct:
public int CompareTo(object obj)
{
if (obj is int)
{
return myIntField.CompareTo((int)obj);
}
return 0;
}
One way would be to create a custom IComparer<T> that compares instances of your struct based only on the value of that field and pass it to this overload of BinarySearch (you will also need to create a "dummy" struct instance to compare to). This is probably the purest solution.
However, as a practical matter you can use LINQ to project into a collection of field values and binary search into that; the resulting index will be the same as if you had searched the struct collection itself. For example:
var structs = new MyStruct[n];
var index = structs.Select(i => i.F).ToList().BinarySearch(42);
In the code above, F is the vame of the field and 42 is the value you are searching for (its type would be the type of F). This is not going to be as fast, but you don't need to write any code and speed could very well be irrelevant in your case.
Update: To clarify: obviously, the code above will be O(n) due to the projection operation so using binary search once after projecting like that is silly (you can simply do a linear search instead). However, if you intend to make multiple searches then it might start making sense.
I would definitely not recommend overriding Equals in your struct unless comparisons between instances are meant to be reduced to comparing F members everywhere in your application.
Let's say I have a data object, but this object can hold one of several types of data.
class Foo
{
int intFoo;
double doubleFoo;
string stringFoo;
}
Now, I want to create an accessor. Some way to get at this data. Obviously, I could create multiple accessors:
public int GetIntFoo();
public double GetDoubleFoo();
public string GetStringFoo();
Or I could create multiple properties
public int IntFoo { get; set; }
public double DoubleFoo { get; set; }
public string StringFoo { get; set; }
I don't that this is a very good design. It requires the client code to be more concerned about type than it should have to be. What's more, I really need only a single value for this class and the above would allow one of each type to be assigned at the same time. Not good.
One option is to use Generics.
class Foo<T>
{
public T TheFoo { get; set; }
}
However, this doesn't create a Foo, it creates a Foo<T>. A different type for each, so I can't really use them as the same type.
I could derive Foo<T> from FooBase, then treat all of them as FooBase's, but then i'm back in the problem of accessing the data.
A different Generics option is to use something like this:
class Foo
{
string stringRepresentationOfFoo;
public T GetFoo<T>() { return /* code to convert string to type */ }
}
OF course the problem is that any kind of T could be passed, and frankly, it's a bit busy.
I could also just box the values and return an object, but then there is no type safety.
Ideally, I want to treat all Foo's the same, but I want type safety so that if there isn't a StringFoo, I can't even compile a reference to a StringFoo.
Foo foo = new Foo("Foo");
string sFoo = foo.Value; // succeeds.
Foo foo = new Foo(0);
int iFoo = foo.Value; // succeeds
string sFoo = foo.Value; // compile error
Perhaps this isn't even possible.. and I'll have to make some compromises, but maybe i'm missing something.
Any ideas?
EDIT:
Ok, so as daniel points out, the compile time checking of a runtime type is not practical.
What is my best option for doing what I want to do here? Namely, Treat all Foo's the same, but still have a relatively sane access mechanism?
EDIT2:
I don't want to convert the value to different types. I want to return the correct type for the value. That is, if it's a double, I don't want to return an int.
How about passing in the variable as a parameter to the get? Like this:
int i = foo.get(i);
Then in your class, you'd have something like:
public int get(int p) {
if(this.type != INTEGER) throw new RuntimeException("Data type mismatch");
return this.intVal;
}
public float get(float p) {
if(this.type != FLOAT) throw new RuntimeException("Data type mismatch");
return this.floatVal;
}
This sort of turns the type checking inside-out: instead of checking what type foo holds, you have foo check what type you want. If it can give you that type, it does, or else it throws a runtime exception.
I don't think this could work (giving you the compiler error you want)
What would you want this to do:
Foo bar = (new Random()).Next(2) == 0 ? new Foo("bar") : new Foo(1);
int baz = bar.Value;
Is that a compiler error?
I think "treat them all the same" (at least the way you've described it) and "compile time error" are going to be mutually exclusive.
In any case, I think the "best way" is going to be a compromise between generics and inheritance. You can define a Foo<T> that is a subclass of Foo; then you can still have collections of Foo.
abstract public class Foo
{
// Common implementation
abstract public object ObjectValue { get; }
}
public class Foo<T> : Foo
{
public Foo(T initialValue)
{
Value = initialValue;
}
public T Value { get; set; }
public object ObjectValue
{
get { return Value; }
}
}
Many systems use a helper methods to return the alternate types just as the .net frameworks base object has the ToString() method
Choose which is the best base type for each of your object and provide To methods for other cases
e.g.
class Foo{
public Int32 Value { get; set; }
public Byte ToByte() { return Convert.ToByte(Value); }
public Double ToDouble() { return (Double)Value; }
public new String ToString() { return Value.ToString("#,###"); }
}
One thing is to store any type in your internal state of the class, and another is to expose it externally. When you write a class, you are actually declaring a contract for its behavior. The way you write it will influence greatly how client code will look like when using the class.
For example, by implementing the IConvertible interface you state that your type can be converted to any CLR type as an equivalent value.
I have also seen implementations where a Value class was used to store results of calculations, results that could represent either a string, double, int or boolean. But, the problem was that client code had to check a Value.Type property of an enum {String, Integer, Double, Boolean} and then either cast the Value.Value property (which was exposed externally by the Value class as an Object type) or use the specific ValueString, ValueDouble, ValueInt, ValueBoolean getters.
Why not just use string, double and int?
After info about collection: What about using object? You will have to check for types and such afterwards anyways. And to help you with that you can use the is and as operators. And the Enumerable.Cast Method, or even better, the Enumerable.OfType Method.
Actually, what is the purpose of this class? The biggest problem seems to be design breaking at least SRP (single responsibility principle).
Nonetheless, if I'm reading it correctly, you'd like to store some value in the container, pass the container to client and type-safely retrieve the value.
With this approach, you can use your proposal, i.e.
namespace Project1 {
public class Class1 {
static int Main(string[] args) {
Foo a = new Foo();
a.SetValue(4);
Console.WriteLine(a.GetValue<int>());
Foo b = new Foo();
a.SetValue("String");
Console.WriteLine(a.GetValue<string>());
Console.ReadLine();
return 0;
}
}
class Foo {
private object value; // watch out for boxing here!
public void SetValue(object value) {
this.value = value;
}
public T GetValue<T>() {
object val = this.value;
if (val == null) { return default(T); } // or throw if you prefer
try {
return (T)val;
}
catch (Exception) {
return default(T);
// cast failed, return default(T) or throw
}
}
}
}
However, in that case why not simply pass data as object and cast by yourself?
Depending on your needs, you may also try "PHP in C#":
namespace Project1 {
public class Class1 {
static int Main(string[] args) {
MyInt a = 1;
MyInt b = "2";
Console.WriteLine(a + b); // writes 3
Console.ReadLine();
return 0;
}
}
class MyInt {
private int value;
public static implicit operator int(MyInt container) {
return container.value;
}
public static implicit operator MyInt(int value) {
MyInt myInt = new MyInt();
myInt.value = value;
return myInt ;
}
public static implicit operator MyInt(string stringedInt) {
MyInt myInt = new MyInt();
myInt.value = int.Parse(stringedInt);
return myInt;
}
}
}
I'm sorry, I just don't buy your premise. If the data all have the same purpose, then they should all have the same type. Consider a class that's meant to hold the current temperature, as returned by one of several web services. All the services return the temperature in Centigrade. But one returns as an int, one returns as a double, and one returns it as a string.
It's not three different types - it's one type - double. You would simply need to convert the non-double returns into double, which is what the temperature is (or maybe float).
In general, if you have multiple representations of one thing, then it's still one thing, not multiple things. Convert the multiple representations into one.