C#: Using a enum to cast one object to a specific object - c#

EDIT: Hopefully this helps, understand what I am trying to do.
I have a object returned which is of type Object, within this object I have a int value,
based on this int value I want to be able to use a enum to tell me what specific object a should case this object to.
The Enum holds all possible casings.
I will receive a generic object (of type object) which can be one of many different more specific objects say in this case of type Model. I want to be able to look inside the object for an int value which will tell me which cast to use.
For instance a have objectA and it has a int value set to '2' within the object, I want to cast this object to my specific object based on my enum value 2, which is set to a specific type.
This may be very simple but cannot work out how you would so this and if it is possible, thank you.
Thanks.

If you mean you want to change the type of the objectA variable at exection time, the answer is no. The compiler needs to know the type of the variable for all kinds of things which are done at compile time.
If you're using C# 4, you may be able to use dynamic to help you - but it's not really clear what you're trying to achieve. In many cases it's a better idea to create a common interface which all of your types implement, and then just make the type of the variable the interface type. That's not universally applicable, but it's a good idea when it works.

Are you trying to typecast one enum to another?
Enum Type1
{
A
B
};
Enum Type2
{
A,
B
};
Type1 type1 = Type1.A;
if(Enum.IsDefined(typeof(Type2), type1.A.ToString())
{
Type2 type2 = (Type2)Enum.Parse(typeof(Type2), type1.A.ToString());
//type2 now holds Type2.A
}
EDIT
If you want to change type of an object at runtime, it is not possible.
If you just mean casting, (same object different representation corresponding to implemented interfaces, base class, etc), it is possible, but here object type does not change.

It's a little hard to understand what you want. But this is my take on it. All your classes would need to implement interface ITypeContainer to be able to extract the enum value.
void Main()
{
....
....
CastToType((ITypeContainer)myObject);
}
public void CastToType(ITypeContainer obj)
{
switch (obj.ObjectType)
{
case TypeEnum.Test1:
var o1 = (Test1)obj;
break;
case TypeEnum.Test2:
var o2 = (Test2)obj;
break;
}
}
public class Test1 : ITypeContainer
{
public TypeEnum ObjectType{ get; set; }
}
public class Test2 : ITypeContainer
{
public TypeEnum ObjectType{ get; set; }
}
public enum TypeEnum
{
Test1,
Test2,
Test3
}
public interface ITypeContainer
{
TypeEnum ObjectType{ get; set; }
}

Related

Create overrideable enum in parent class

I want to create a nested structure where every class represents a country, inheriting the same parent class Country. Each child class should have an enum representing the different states States.
The goal is being able to select a country, then one of its states.
The Content will be saved into a dictionary Dictionary<Tuple<string, Type>, object> where the Types would be Country and Country.States.
I tried making an interface/abstract class with an enum called States to be implemented, but this does not work, as it is a type definition.
Is there any workaround?
public abstract class Country
{
public abstract enum States { get; }
}
public class CountryA : Country
{
public new enum States
{
StateA,
StateB,
StateC,
}
}
Your design is flawed, you need to create a single Country class with a property e.g. public string[] States { get; set; }.
Then create instances (objects) of your Country class, each with States set to the items that are needed:
var usa = new Country { Name = "USA", States = new[] { "Alabama", ... } };
var canada = new Country { Name = "Canada", States = new[] { ... } };
// etc
You have a few options:
You can create an enum at runtime (see here: Dynamically create an enum), but I don't think that'll suit your needs, as I imagine you're going down the enum route for ease of use in coding than anything else.
You could implement a typesafe enum pattern (see here: typesafe enum pattern), but that's even more coding just for the ability to use a design that mimics enums while your coding the rest of your logic.
My advice is to use a dictionary and build your 'states' at instantiation from a settings file or external data source. After all, countries and their states/cities/etc do change names from time to time. Locking yourself into a hard-coded situation like what you're aiming for isn't going to support such future changes.
Good luck!
[Edited following response from camilo-terevinto]
While I certainly agree that your design is most likely flawed, since you'd need hundreds of classes and enums, I disagree entirely with the other answers that "it is not possible".
It's certainly possible using generics (while keeping in mind you cannot restrict entirely to Enums):
public abstract class Country<TStates>
where TStates: struct, IConvertible, IFormattable, IComparable
{
public abstract TStates[] States { get; }
}
public enum UnitedStatesStates
{
WhoCares, WhoCares2
}
public class UnitedStatesCountry : Country<UnitedStatesStates>
{
public override UnitedStatesStates[] States { get; }
}
Now, I highly doubt this will be useful in the (not-so-long) term.
You are asking to make enum inheritable, this is possible to achieve if you don't use enum, but a class with static public members (which can be inherited and have different set of members per type). It behave nearly as enum:
public class Country1
{
public static State State1 { get; } = new State("State 1");
public static State State2 { get; } = new State("State 2");
...
}
It should be clear what Country1.State1 is, right? The State can be a more complex object than just a string. It doesn't require inheritance as you can see, because country define states as different members.
You can follow same principle to implement long chain of objects: Planet.Continent.Country.State.Province.Town.Street.Hause..
You say
Content will be saved into a dictionary Dictionary<Tuple<string, Type>, object> where the Types would be Country and Country.States.
Don't. Those are different types, that's a poor choice of a key. If you need to enumerate (to find) states, then just add another member to a Country:
public static IEnumerable<State> States
{
get
{
yield return State1;
yield return State2;
...
}
}
Then the searching for something can be a simple linq:
var stateAInCountry1 = ...Countries.OfType<Contry1>().Single().States.Single(o => o.Name == "A");
var countriesWithStateA = ...Countries.Where(o => o.States.Any(o => o.Name == "A"));
Not sure what problem are you solving by introducing a dictionary, but you can initialize additional data structure with proper key if you provided a way to iterate with easy.
It is not so clear to me, if there is anything else you want to achieve, besides being reminded by the compiler to define these different (!) enums.
Actually they have nothing in common to begin with, so neither the compiler nor you can draw any advantage of that contract.
What you could do is declare it as
public abstract string[] States {get;}
and obtain these strings from the individual enums you define in the derived classes. Then the common thing would probably be that you want the string result for informative purposes or something.

Exclude complex property with reflection get properties [duplicate]

Is it possible when looking at a class' properties to detect if any of them is a reference type.
Take below as an example:
public class Client
{
public int Id { get; set; }
public string Name { get; set; }
}
public class ProgrammeClient
{
public int Id { get; set; }
public bool IsActive { get; set; }
public IClient Client { get; set; }
}
ProgrammeClient: -
Id and IsActive are properties but Client is a reference type. Is there a way of detecting this?
Many thanks,
Kohan.
Addendum
The reason i ask is: I am using a mapper that checks types are the same before matching property names and copying the values. My hope is to detect classes and override the type matching and simply copy the classes properties if the THEY type match.
Well, it sounds like you may be trying to detect the difference between a value type and a reference type. You can find that out using Type.IsValueType... but be aware that value types can easily have properties too. (Think about DateTime for example.) Also, some types which you may want to regard as "not objects" are reference types - string being a prime example.
Another option would be to use Type.IsPrimitive - is that what you're looking for? If so, you should be aware that decimal, DateTime and string are not primitive types.
If you can describe exactly what makes a type an "object" in your way of thinking (or rather, in whatever way makes a semantic difference in what you're trying to do with your type). I suspect you don't currently have a very clear set of criteria - coming up with those criteria may well clarify other aspects of your current task, too.
You can use a little reflection to see if a property is a value type or a class type. Class is probably what you mean by "object". All types in .NET derive from the object type.
Client.GetType().IsClass
Or you can loop through all properties and see which are compound
foreach(var p in ProgrammeClient.GetType().GetProperties())
{
if(p.PropertyType.IsClass) Console.WriteLine("Found a class");
}
Check if the type is a string and check if it is a class.
public static bool IsNonStringClass(this Type type)
{
if (type == null || type == typeof(string))
return false;
return typeof(Type).IsClass;
}
All properties in your example return objects, as everything is an object in .NET; int and bool are objects. If you mean a reference type, as opposed to value types, then you can do the following:
foreach (PropertyInfo pi in typeof(Client).GetProperties()) {
if (pi.PropertyType.IsClass) {
// reference type
// DoMyFunkyStuff
}
}
You can enumerate the properties via Reflection, and check them:
bool ContainsOnlyValues() {
return typeof(ProgrammeClient).GetProperties().All(x => x.PropertyType.IsValueType);
}
The Type.IsvalueType property can reveal this.
Id.GetType().IsValueType
This will be True for Id, false for a class
If using TypeSupport nuget package you can simply do:
typeof(ProgrammeClient).GetExtendedType().IsReferenceType;
TypeSupport does inspection and provides deeper insight on the capabilities of a given type, handling things like strings, enums etc and makes it easier to code these types of things.

Why can't I cast from 1 type to another when both share interface

This is a demo console app (Which you should be able to just copy and paste into VS if you wanted)
public class Program
{
static void Main(string[] args)
{
Temporary t = new Temporary(); //I know it should be ICompany t
t.Name = "My Name";
var com = (ICompany)t;
var result = (Company)com; //Kaboom
}
}
public class Temporary : ICompany
{
public string Name { get; set; }
}
public class Company : ICompany
{
public string Name { get; set; }
}
public interface ICompany
{
string Name { get; }
}
Hopefully the code above is straight forward.
My question is about the cast and why it fails. I know I can change the original variable t to type ICompany (As per the comments), but my quesiton is about why the cast fails as it currently is.
My understanding (which hopefully explains where I'm going wrong) is
var com = (ICompany)t
Cast t, which is of Type Temporary into ICompany. This works great as Temporary implementsICompany`
This means, t is now of type ICompany. So, hopefully
var result = (Company)com; //Kaboom
this converts com (type ICompany) into Company
Why does this fail and why does it know that t is still of type Temporary
There is some confusion in this question, which is probably what prompted it.
This statement:
This means, t is now of type ICompany. So, hopefully
is incorrect. No, t is still of type Temporary, as per its declaration:
Temporary t = new Temporary();
There are actually two places in this line where type is important. It is the actual type of the object you constructed, and the type of the variable you placed the reference into.
Sure, you could write it like this:
ICompany t = new Temporary();
But that would only change the type of the variable, the underlying object is still of type Temporary.
You're then trying to cast the actual object, which is still a Temporary, into a Company, but this will fail, since a Temporary is not a Company.
They both, however, implement the same ICompany interface, which is great, you can talk to both types of objects with only the knowledge that they implement something in common, but it is not the same type of object and you cannot convert from one to another.
Just because com is an ICompany it doesn't mean it points to a Company instance. It could point to a (potentially) infinite number of types that derive from ICompany. Yes, you can look at the code and know this, but that's not how the compiler see it.
This is especially true in your case as the actual type is Temporary, not Company.
You can't just cast the Company class into the Temporary class, because although they both derivate from ICompany and have the same fields, the compiler still thinks that they're different classes. The only allowed kind of class casting is from a child class to its parent class. In that case, you will in fact put a "mask" on the child class which hides its exclusive fields, and that will have it behave as its parent, but you still will be able to convert it back to the original child class.
You cannot cast an interface to a implementation like that. Casting is NOT a conversion. Casting only means: "take this item and treat it as if it was some other type", but the data underneath remains the same. This way you can cast any speciffic type to more general one - the other way is allowed only if object beneath is of type you are casting to (or to some other, iherited type). Imagine that your classes definitions would look like this:
public class Temporary : ICompany
{
public string Name { get; set; }
}
public class Company : ICompany
{
public string Name { get; set; }
public string OtherProperty {get; set;}
}
If you'd call ((Company)t).OtherProperty, you'd try to use a property, that Temporary t object doesn't possess. Compiler does not let you to do so.

Nullable Generic Declaration?

Say I have an object,
Class A<T, T2>
{
public T MyObject {get;set;}
public IList<A<T2>> MyChildren {get;set;}
}
Problem is, sometimes I dont have children, so I dont want to declare the children type aka T2, any idea? I cannot pass in like
A a = new A<string, Nullable>(); as it is throwing an error.
Thanks
There's no way to specify a "null" for a Generic Type parameter - if you declare them on the class, they're mandatory when you use that class.
If you think about it, this makes sense, because without T2, your class will be partially undefined, which isn't something that machines can handle well.
What you probably need to do is to split your class into two. First, your class with no children:
class Widget<T>
{
public T MyObject { get; set; }
}
Then, an extension that adds support for children:
class WidgetWithChildren<T,T2>: Widget<T>
{
public IList<Widget<T>> MyChildren { get; set; }
}
Though, that's only a partial solution, as you don't get a way to handle grandchildren.
Nullable is a genric it self so you have to do something like
new A<string, Nullable<?>>();
You use Nullable to make Value types (e.g. int) able to be null but if you use a Referense Type (e.g. class) it can be null anyway.
My tip is to use a base class for A, if you don't have one use Object.
new A<string, Object>();

Property type depends on enum value

How should i implement, in C#, a class containing a property with the type of something and then that something example :
public class MyObject{
public someEnum e { get; set;}
public Object ObjectDependentOnE { get; set; }
}
I want to be able to return the right type for my object which depends on my enum.
for example if e = 1, my object is of type T1...
or maybe I trying to do somethng wrong
any idea?
I am unsure of what you are really trying to do, but it appears that generics is what you are looking for:
public class MyObject<T>
{
public T SomeProperty{get;set;}
}
You can constraint T to classes that implement a given interface.
Usage would be:
MyObject<SomethingClass> something = new MyObject<SomethingClass>;
I'm not sure what your use case would be - more information might help answer this better, but from my guess, you may want to consider making a factory class instead. Something like:
class MyClass
{
public SomeEnum E { get; set; }
// This might be better as : public Object GetTheObject(SomeEnum E) and eliminating the above property
public Object GetTheObject()
{
switch(this.E)
{
case E.Something:
return new MySomethingObject(); // Or return an instance that already exists...?
default:
return new MyDefaultObject();
}
}
}
This could also be a property with a getter and setter, and get and set the specific object type.
However, I recommend considering rethinking the approach - this seems like a very error-prone design, since it has no type safety at compile time, and is very confusing from the consumer's POV.

Categories