I have a sql stored procedure that I run that returns a class name. For example it returns "orange". I have a class called "orange". Is it possible to use that return string to access orange.GrabFiles?
Thanks!
You can use System.Reflection to get the class which you need and invoke the method you want to call.
To do this you can iterate though all types of the assembly and pick the right one for you. If you have special names you can use attributes to link a specific type with a special name.
Search the type
// Type to find
String name = "orange";
// I assume you only use one assembly
Assembly asm = Assembly.GetCallingAssembly();
// Iterate though all types
foreach (Type item in asm.GetTypes())
{
if (item.Name == name)
{
return item;
}
else
{
// A class can have multiple SpecialNameAttributes, this is a attribute you have to create
SpecialNameAttribute[] attributes = (SpecialNameAttribute[])item.GetCustomAttributes(typeof(SpecialNameAttribute));
foreach (SpecialNameAttribute attribute in attributes)
{
if (attribute.Name == name) return item;
}
}
}
return null;
Invoke the method
With instance creation:
Object instance = Activator.CreateInstance(typeFound);
typeFound.GetMethod("GrabFiles").Invoke(instance, ...);
Without instance:
typeFound.GetMethod("GrabFiles").Invoke(null, ...);
Assuming the namespace for "orange" is "fruits" you can do the following:
dynamic d = Activator.CreateInstance(Type.GetType("fruits.orange"));
d.GrabFiles();
Quite simple and straight-forward as long as you know what your code is doing.
If there are only a few return values, all known at compile time, then it will be simpler to check the result and branch accordingly (using switch or a sequence of ifs).
If you need more dynamic behaviour you can do Type typeToCall = Type.GetType(typeName); and then use typeToCall.InvokeMember(...).
Related
I have a WebApi which has some action methods that accepts an XMLDocument value. Inside these functions I converted that XML to AnonymousObject, then, I do my logic.
Now, I got the XML with empty attributes, and I need to do a check which can check all properties in that anonymous object if which are null or empty, I did something there but it didn't work, although, I passed an XML with empty attributes.
<Students>
<Student ID="" Name="" />
<Student ID="" Name="" />
</Students>
This was an example of XML inputs which I got, and there are some other forms for the same, so, I wrote a function that checks if the attributes are empty or not after deserializing the XML to an anonymous object as follows:
//This handles the conversion from XML to the anonymous object
XDocument doc;
using (var sr = new StringReader(request.InnerXml))
{
doc = XDocument.Load(sr);
}
var clientList = doc.Descendants()
.Where(d => string.Equals(d.Name.LocalName, "Student", StringComparison.OrdinalIgnoreCase))
.Select(
d =>
new
{
studentId = d.Attributes().SingleOrDefault(a =>
string.Equals(a.Name.LocalName, "ID", StringComparison.OrdinalIgnoreCase))
?.Value,
studentName = d.Attributes().SingleOrDefault(a =>
string.Equals(a.Name.LocalName, "Name", StringComparison.OrdinalIgnoreCase))
?.Value
}).ToList();
Then I wrote that function which should validate that anonymous object's properties, all should have a value, but if I passed the above XML, it will return FALSE as if there is no property with empty value:
public static bool IsAnyNullOrEmpty(object objectToBeChecked)
{
try
{
foreach (PropertyInfo pi in objectToBeChecked.GetType().GetProperties())
{
if (pi.PropertyType == typeof(string))
{
string value = (string)pi.GetValue(objectToBeChecked);
if (string.IsNullOrEmpty(value))
{
return true;
}
}
}
return false;
//return objectToBeChecked.GetType().GetProperties()
// .Where(pi => pi.GetValue(objectToBeChecked) is string)
// .Select(pi => (string) pi.GetValue(objectToBeChecked))
// .Any(string.IsNullOrEmpty);
}
catch (Exception ex)
{
return true;
}
}
Any advice?
EDIT #1
While debugging I noticed that:
Property Name: <>f__AnonymousType3`1
Property Type: Name = "<>f__AnonymousType3`1" FullName = "<>f__AnonymousType3`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]"
I strongly suggest to use a named class instead of an anonymous one for that. Obviously you have some strong knowledge on what properties the instances in the xml expose, so there´s no use on hiding this knowledge away.
Imagine some day you don´t want only string-properties but also numbers. Then you´d have to re-invent great parts ofyour logic, not only the validation but only the actual work with the objects.
I suppose you want to do more than just validating your objects. You surely want to do something with them. In order to do so you need to know what members they expose. In your current implementation they´re just objects, which don´t expose much to their clients. So in order to do anything you´d need something like this:
var a = ((theType) myInstance).StudentName;
But you´ve lost all information about what theType actually is, so all you can do with the object is calling ToString, Equals and some other members derived from object.
In your special case you allready know that the instance in your xml has a StudentName- and a studentId-property. So why should you throw that away and do as if you didn´t know that?
As of MSDN:
To pass an anonymous type, or a collection that contains anonymous types, as an argument to a method, you can declare the parameter as type object. However, doing this defeats the purpose of strong typing. If you must
store query results or pass them outside the method boundary, consider
using an ordinary named struct or class instead of an anonymous type.
I solved it like that:
public static bool IsAnyNullOrEmpty(object objectToBeChecked, params string[] parametersToBeChecked)
{
foreach (var obj in (IEnumerable)objectToBeChecked)
{
foreach (var pi in obj.GetType().GetProperties())
{
if (parametersToBeChecked.Contains(pi.Name))
{
var value = (string)pi.GetValue(obj);
if (string.IsNullOrEmpty(value))
{
return true;
}
}
}
}
return false;
}
This will take the object (anonymous object) and properties names which you want to check, this works for me.
you need to use a concrete class implementation if you want to pass your object in some method.
Copy your xml structur and let Visual Studio create a deserialization class for you.
Edit -> Paste Special -> Paste Xml as Class
If you know your Xml-Structur, why you want to loose that information.
I need to define a type of object, i recieve from service. Service has different namespace, but same object, so i wrote some parser to get names of recieved types.
But i have some troubles to detect nested list types like
List<List<SomeObjectType>>
or
List<List<Tuple<int,int,SomeObjectType>>
So in my recursive function i need to make a list type with sample element type. Like this:
public Type getType(TypeSpec TypeInfo, string NameSpace)
{
Type foundType = ObjectsHelper.ByName(NameSpace + "." + nameOfType);
if (foundType == null) throw new TypeNotFoundException(TypeInfo.name);
else
{
if (TypeInfo.generic_params != null && TypeInfo.generic_params.Count > 0) // if has generic params, run recursive
{
var listOfParams = new List<Type>();
foreach (var gp in generic_params)
{
listOfParams.Add(this.getType(gp, NameSpace));
}
// here is a heart of the matter
HowToAddGenericParameters(foundType, listOfParams); // ????
}
return foundType;
}
}
Is it possible? =)
It seems you are looking for MakeGenericType method
foundType.MakeGenericType(listOfParams.ToArray());
How do I determine if a property is a user-defined type? I tried to use IsClass as shown below but its value was true for String properties (and who knows what else).
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass) {
// do something with property
}
}
* Updated for more clarity *
I am trying to traverse a given type's definition and if the given type or any of its public properties are defined within the assembly, I am searching for an embedded JavaScript document. I just don't want to waste processing resources and time on native .NET types.
#Bobson made a really good point:
"...Unlike some other languages, C# does not make any actual
distinction between "user-defined" and "standard" types."
Technically, #Bobson gave the answer; there is no distinguishing difference between a user-defined type and one defined in the .NET Framework or any other assembly for that matter.
However, I found a couple useful ways to determine if a type is user-defined.
To search for all types defined within the given type's assembly, this works great:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& property.PropertyType.Assembly.FullName == type.Assembly.FullName) {
// do something with property
}
}
If the types can be defined in various assemblies, excluding the System namespace works in most cases:
foreach (var property in type.GetProperties()) {
if (property.PropertyType.IsClass
&& !property.PropertyType.FullName.StartsWith("System.")) {
// do something with property
}
}
If by "user-defined" you mean that it is not part of the standard assembly (mscorlib) then you can do something along the lines of this:
if(typeof(SomeType).Assembly.GetName().Name != "mscorlib") {
// user-defined!
}
However this will also consider types from external assemblies (aka: libraries) to be considered "user-defined". If you only want those in your current assembly then you can use
typeof(SomeType).Assembly == Assembly.GetExecutingAssembly()
I wrote a generic populator for unit testing that assigns predictable values to my objects and came across this kind of problem. In my case I wanted to know which of my properties were objects so that I could recursively populate those object properties, again with predictable values.
It seemed to me that introducing an interface implemented only by the classes that I was interested in traversing was the best way to do this. You can then test to see if your property is an object of interest:
public static bool IsMyInterface(this Type propertyType)
{
return propertyType.GetInterface("MyInterfaceName") != null;
}
Say your project is named "Foobar" and everything you make is under that namespace. You can test to see if you've written it by the following method:
typeof(SomeType).Namespace.Contains("Foobar");
I struggled with this as well when creating a log when updating the database. I did not want the classes to be shown in the log as they never == between data and dto.
foreach (PropertyType item in properties)
{
if((item.PropertyType.IsClass && item.PropertyType.FullName.StartsWith("System.")) || !item.PropertyType.IsClass)
{
//...do stuff
}
}
This allowed me to deal with strings and the likes which are flagged as classes.
If by "user-defined" type you mean type that was declared in your executing assembly then you can obtain list of that types like in this sample c# console application:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var localTypes = currentAssembly.GetTypes();
}
}
UPDATE:
If you want to obtain list of types from all referenced assemblies:
class Program
{
static void Main( string[] args )
{
var currentAssembly = Assembly.GetExecutingAssembly();
var referencedAssemblies = currentAssembly.GetReferencedAssemblies();
var typesFromReferencedAssemblies = referencedAssemblies.Select( assemblyName => Assembly.ReflectionOnlyLoad( assemblyName.FullName ) ).SelectMany( assembly => assembly.GetTypes() );
}
}
Just be aware that Program type will also be in that list. Is this sufficient answer to your problem?
I want to use something similar as:
object ob;
var props = ob.GetType().GetProperties();
List<Element> list = new List<Element>();
foreach (var prop in props)
{
if (prop.PropertyType == typeof(String))
list.Add(makeStringProperty(prop));
else if (prop.PropertyType == typeof(int))
list.Add(makeIntProperty(prop));
else
{
}
}
which adds something to the given list for every property in a given object. Now I want to add a clause for also adding enum-variables, including getting all its values by Enum.GetValues() f.e..
That would be easy for any one given enum, but I want this to be generic for every possible enum,
so for example if ob would have:
enum Weather {
sunny,
rainy,
cloudy
}
Weather weather = sunny;
enum Places {
beach,
mall,
home
}
Places place = beach;
I would be able to get both variables themselves AND all the values of both Enums.
Of course I can't directly check typeof(Enum) or anything.
Does someone have a clue?
else if(prop.PropertyType.IsEnum)
{
var values = Enum.GetValues(prop.PropertyType);
}
It's something like
typeof(Weather).GetFields()
or
ob.GetType().GetFields()
if you want to use reflection directly on an enum type. The members of an enum are a kind of static fields.
But you can also use
Enum.GetValues(ob.GetType())
In any case, if there's doubt, you should check if it is an enum or not first:
var typeOfOb = ob.GetType();
if (typeOfOb.IsEnum)
{
// use Enum.GetValues(typeOfOb) here
}
Note: System.Type is the class used for both a type determined compile-time, like typeof(Weather), and a type determined run-time, like ob.GetType(). So you can use both as an argument to the GetValues(System.Type) static method.
I'm trying to write a custom method to populate a ListView control using Generics:
private void BindDataToListView(List<T> containerItems)
{
this.View = View.Details;
this.GridLines = true;
this.FullRowSelect = true;
if (this.Items.Count > 0)
this.Items.Clear();
this.BeginUpdate();
int i = 0;
foreach (T item in containerItems)
{
// do something
}
this.EndUpdate();
}
The parameter containerItems can have many items since I'm using generics. But I get stuck in the foreach loop. How do I access the values in containerItems?
Do I have to use reflection on each instance of T in the foreach loop? I think I do to retrieve the property name. But once I have the property name of the type T, how do I retrieve the value?
The most common way of doing this (with winforms) is via TypeDescriptor; this allow you to use things DataTable the same as classes; the "full" pattern is quite complex (and involves checking for IListSource, ITypedList, etc; however, the short version is; to get the available properties:
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
To get a named property:
PropertDescriptor prop = props[propName];
To get a value for an instance (sourceObject):
object val = prop.GetValue(sourceObject);
To render a value as a string (using the designated converter):
string s = prop.Converter.ConvertToString(val);
You could limit T to an interface, and use that interface in the iteration.
What does T represent ?
Like it is now, it is a generic type and it can be ... anything.
So, what I would do, is create an interface IListViewBindable or something like that. That interface could then have a method 'CreateListViewItem' for instance.
Then, I would change the method, so that a constraint is applied to your type-parameter T, saying that T should implement IListViewBindable, like this:
public void BindDataToListView<T>( List<T> containerItems ) where T : IListViewBindable
{}
In your BindDataToListView method, you could then do this:
foreach( T item in containerItems )
{
this.Items.Add (item.CreateListViewItem());
}
If the items in the list are of totally unconstrained type, then you can treat them as simply of type object. You call GetType() to get the type of the object. On that you can call GetProperties() to get an array of PropertyInfo objects. And on those you can call GetValue() to retrieve the value of the property.
If you already know the name of a property, just call GetProperty() to retrieve it:
string valueAsString = item.GetType().GetProperty("Something")
.GetValue(item, null).ToString();
I don't completely understand what you're asking, but I think that this will point you in the right direction. Please ask for clarification if it looks like it can help and it's unclear.
You can access a given property of an object using reflection via
object o;
PropertyInfo info = o.GetType().GetProperty().GetProperty("NameOfPropertyIWant");
and you can get the value via
object value = info.GetValue(o, null);
Now, if you're going to be accessing a property of the same name on objects of various types, you should consider adding an interface
public interface IHasThePropertyIWant {
object NameOfPropertyIWant { get; }
}
Then you can enforce this via
void BindDataToListView(List<T> containerItems) where T : IHasThePropertyIWant
and use it in the look like so
foreach (T item in containerItems) {
object o = item.NameOfPropertyIWant;
// do something with o
}
ObjectListView uses reflection to do exactly what you are trying to do: populate a ListView using reflection. You could save yourself a lot of trouble by using it. It has already solved all the tricky problems you are going to encounter on this path.
If you really, really want to do it yourself, Marc's answer is (of course) completely correct.