Grade in an Enum Structure.
var y=1;
var x= (Grade)y;
I'm trying to do the same thing as the above line but with a dynamic CLASSNAME.
FieldInfo field = typeof(Person).GetField("Grade");
var x= Convert.ChangeType(y ,field.FieldType);
I tried that. this works fine but not for enums.
I think the problem is with the way you are accessing the field on the enum. Enum fields are static. By default, the Type.GetField method uses binding flags equivalent to BindingFlags.Public|BindingFlags.Instance. This won't match an enum member.
If this is the problem you are having, then you can use typeof(Person).GetField("Grade",BindingFlags.Public|BindingFlags.Static) to get the FieldInfo for the field named "Grade" on the enum type named "Person". This assumes that your model looks like:
enum Person
{
Grade
}
There's another problem with your code that is compatible with enums as well. It's not totally obvious because your example seems to treat "Grade" as both a field and an type. If my previous suggestion doesn't describe your model, and the following does, then the problem is that you are using Convert.ChangeType which in this case should give you an InvalidCastException.
You need to find a different way to cast the value to your enum. If the class name is not known at compile-time, then I would suggest using linq expressions, e.g.
Type targetEnumType = typeof(Person).GetField("Grade");
ConstantExpression runtimeValue = Expression.Constant(y);
UnaryExpression cast = Expression.Convert(runtimeValue,targetEnumType);
LambdaExpression lambda = Expression.Lambda(cast);
Delegate getTheCastValue = lambda.Compile();
object value = getTheCastValue.DynamicInvoke();
This code assumes that your model looks something like
class Person
{
public Grade Grade;
}
enum Grade
{
First = 1,
Second = 2
}
However, looking at this, it becomes obvious that if Person is a non-generic class, then you would have to know the type of the Grade field at runtime, so you are better off just doing a (Grade)y cast, like in your example.
Related
I dont know how to describe the problem, so weird. I have function like this:
long getPersonId(...){
//...
}
The above function returns Id of a person based on some arguments.
So I logged the return value of the function and it is 1.
Then I have code like this:
person = myMap.get(getPersonId(..))
which returns null object but this returns a valid Person object, why?:
person = myMap.get(1)
But as I described before getPersonId(..) returns 1, which basically means
myMap.get(getPersonId(..)) == myMap.get(1)
myMap is typed as Map<Long, Person> myMap
What is happening here?
In Groovy, as in Java, 1 is an int literal, not a long, so
myMap.get(1)
is attempting to look up the key Integer.valueOf(1), whereas
myMap.get(getPersonId(..))
is looking up the key Long.valueOf(getPersonId(...)). You need to make sure that when you populate the map you are definitely using Long keys rather than Integer ones, e.g.
myMap.put(1L, somePerson)
In your original version of this question you were calling the GORM get method on a domain class rather than the java.util.Map.get method, and that should work as required as the GORM method call converts the ID to the appropriate type for you before passing it on to Hibernate.
I am so sorry the problem was when I initialize the map myMap
Map<Long, Person> myMap = [1, new Person()]
when you say something like this the key is an integerbut not a long still groovy not complaining.
So the problem is my method was returning a long value (1L) but my actual key on the map is integer value(1).
So changing my map init to Map<Long, Person> myMap = [1L, new Person()] solved the problem.
Probably this due to dynamic nature groovy but irritating unless you know how dynamic langs behave lol.
EDIT: Added a more complete example, which clarified the problem.
Some .NET attributes require a parameter of type Type. How does one declare these parameters in F#?
For example, in C# we can do this:
[XmlInclude(typeof(Car))]
[XmlInclude(typeof(Truck))]
class Vehicle { }
class Car : Vehicle { }
class Truck : Vehicle { }
But, in F# the following...
[<XmlInclude(typeof<Car>)>]
[<XmlInclude(typeof<Truck>)>]
type Vehicle() = class end
type Car() = inherit Vehicle()
type Truck() = inherit Car()
...results in a compiler error: This is not a constant expression or valid custom attribute value.
You should address a circular type dependency introduced by forward usage of types in attributes. The snippet below shows how this can be done in F#:
// Compiles OK
[<AttributeUsage(AttributeTargets.All, AllowMultiple=true)>]
type XmlInclude(t:System.Type) =
inherit System.Attribute()
[<XmlInclude(typeof<Car>)>]
[<XmlInclude(typeof<Truck>)>]
type Vehicle() = class end
and Car() = inherit Vehicle()
and Truck() = inherit Car()
Can you try putting together a more complete example that gives the error? I just quickly tried something similar and it works fine (in F# 3.0 in Visual Studio 2012):
type Car = C
type XmlInclude(typ:System.Type) =
inherit System.Attribute()
[<XmlInclude(typeof<Car>)>]
let foo = 0
I guess there is some tiny detail somewhere that confuses the F# compiler for some reason - but it should understand typeof (which is, in reality, a function) and allow its use in attributes.
I've got a problem here. (C#)
There's a collection in another assembly (I cannot change it) that takes a string as parameter and returns an object.
Like:
object Value = ThatCollection.GetValue("ParameterName");
The problem is, for each parameter string, it returns a DIFFERENT type as object.
What I want is to cast those objects to their respective types, knowing the types only at runtime by their string names.
I need to do some operations with those returned values.
And for that I need to cast them properly in order to access their members and so.
Limitations:
I cannot use "dynamic" since my code needs to be done in an older framework: 3.5 (because of interop issues).
I need to do operations with MANY returned values of different types (no common interfaces nor base classes, except "object", of course)
All I have is a table (containing string values) correlating the parameter names with their returned types.
Yes, I could transform that table into a biiig "switch" statement, not very nice, don't want that.
Any hints??
You want to look into reflection, something like the following should work to cast an object to type T. Set up a simple cast method:
public static T CastToType<T>(object o)
{
return (T)o;
}
Invoke this using reflection:
Type t = Type.GetType(stringName)
MethodInfo castTypeMethod = this.GetType().GetMethod("CastToType").MakeGenericMethod(t);
object castedObject = castTypeMethod .Invoke(null, new object[] { obj });
Scenario:
I have x number of classes. Lets say 10; Each class does different UI Functions. When a user loads a file, that extension tells the program the classname to load; but it's in the form of a string.
Is there anyway to pass a string off as a classname? Something to the effect of.
var classname = "Booger";
var nose = new classname(){ //classname really means "Booger"
//Do Operation
}
You can reflect a type by name using var t = Type.from_name(classname);, however, this works on all types, including enums and structs and it might be the type Type.INVALID. You should probably do some checks, like t.is_a(typeof(MyParentClass)).
You can then instantiate a copy using var obj = Object.new(t);. The whole thing would look like:
var classname = "Booger";
var t = Type.from_name(classname);
if (t.is_a(typeof(MyParentClass)))
return Object.new(t);
else
return null;
It's also worth noting that the run-time type names have the namespace prepended, so you might want to do "MyNs" + classname. You can check in either the generated C or doing typeof(MyClass).name().
I've had the same problem as the OP in regards to getting an assertion error against null. If you take a look at the Glib documentation (in C) it mentions you have to register your class by actually specifying the class name first before you can actually use a string representation of your class name.
In other words you have to use your class first BEFORE you can instantiate a copy of your class with Glib.Type.from_name ("ClassName").
You can use your class first by instantiating a class instance or by getting type information for your class.
var type = typeof (MyClass);
var type_from_string = Type.from_name ("MyClass");
Furthermore, when you use Object.new to create a class there are two things you need to be aware of:
1) You need to cast the return value to get your specific class or base class.
var instance_of_my_class = Object.new (type) as MyClass;
2) Constructors for your class will no longer be called (I don't why). You will need to use the GObject style constructor inside your class:
construct {
pizza = 5;
}
In Groovy you can do surprising type conversions using either the as operator or the asType method. Examples include
Short s = new Integer(6) as Short
List collection = new HashSet().asType(List)
I'm surprised that I can convert from an Integer to a Short and from a Set to a List, because there is no "is a" relationship between these types, although they do share a common ancestor.
For example, the following code is equivalent to the Integer/Short example in terms of the
relationship between the types involved in the conversion
class Parent {}
class Child1 extends Parent {}
class Child2 extends Parent {}
def c = new Child1() as Child2
But of course this example fails. What exactly are the type conversion rules behind the as operator and the asType method?
I believe the default asType behaviour can be found in: org.codehaus.groovy.runtime.DefaultGroovyMethods.java
org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation.java.
Starting from DefaultGroovyMethods it is quite easy to follow the behavior of asType for a specific object type and requested type combination.
According to what Ruben has already pointed out the end result of:
Set collection = new HashSet().asType(List)
is
Set collection = new ArrayList( new HashSet() )
The asType method recognizes you are wanting a List and being the fact HashSet is a Collection, it just uses ArrayList's constructor which takes a Collection.
As for the numbers one, it converts the Integer into a Number, then calls the shortValue method.
I didn't realize there was so much logic in converting references/values like this, my sincere gratitude to Ruben for pointing out the source, I'll be making quite a few blog posts over this topic.