Non-static method requires a target in PropertyInfo.SetValue - c#

Ok, so I'm learning about generics and I'm trying to make this thing run, but its keep saying me the same error. Here's the code:
public static T Test<T>(MyClass myClass) where T : MyClass2
{
var result = default(T);
var resultType = typeof(T);
var fromClass = myClass.GetType();
var toProperties = resultType.GetProperties();
foreach (var propertyInfo in toProperties)
{
var fromProperty = fromClass.GetProperty(propertyInfo.Name);
if (fromProperty != null)
propertyInfo.SetValue(result, fromProperty, null );
}
return result;
}

This happens because default(T) returns null because T represents a reference type. Default values for reference types are null.
You could change your method to:
public static T Test<T>(MyClass myClass) where T : MyClass2, new()
{
var result = new T();
...
}
and then it will work as you want it to. Of course, MyClass2 and its descendants must have a parameterless constructor now.

The problem here is that T derives from MyClass and is hence a reference type. So the expression default(T) will return the value null. The following call to SetValue is operating an a null value but the property is an instance property hence you get the specified message.
You'll need to do one of the following
Pass a real instance of T to the Test function to set the property values on
Only set the static properties on the type

Instead of
propertyInfo.SetValue(result, fromProperty, null);
try:
foreach (var propertyInfo in toProperties)
{
propertyInfo.GetSetMethod().Invoke(MyClass2, new object[]
{
MyClass.GetType().GetProperty(propertyInfo.Name).
GetGetMethod().Invoke(MyClass, null)
});
}

Related

Can I call the "Set" method of a struct property using reflection?

I define a struct:
public struct Settable
{
public string SettableProperty { get; set; }
}
I can set the value of the struct's property in the usual way:
s.SettableProperty = "Abc";
However, when I create a method to attempt to set the property by reflection:
public T CreateWithValue<T>(string propName, string propValue)
{
var retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
var _ = prop.SetMethod.Invoke(retObj, new object[] { propValue});
return retObj;
}
...and call it thus:
var x = CreateWithValue<Settable>("SettableProperty", "Abc");
...I end up with SettableProperty initialized to its default value, null. (No exception is thrown.)
Note that if I define Settable as a class instead of a struct, the value is set as expected.
Is it possible to set struct properties using reflection?
The problem here is that retObj is T, a value-type, but Invoke takes object. This boxes the value, which creates an isolated copy on the heap (inside the box), which you then mutate. Your local copy in retObj isn't impacted in any way here, since it is a completely disconnected copy of the value.
Consider instead:
public T CreateWithValue<T>(string propName, string propValue)
{
object retObj = Activator.CreateInstance<T>();
var prop = typeof(T).GetProperty(propName);
prop.SetMethod.Invoke(retObj, new object[] { typedValue });
return (T)retObj;
}
This creates the box earlier, and unboxes it to get the modified value. It is, however, not very efficient (note: I haven't added any inefficiency; the inefficiency is inherent when using an object API with a value-type). You can remove the allocations if you're happy to get much much dirtier.

Object nulled when cast into type

This is my code
public virtual T GetRepository<T>()
where T : class
{
var type = typeof ( T );
var properties = this.GetType().GetProperties();
foreach ( var property in properties )
{
var name = property.Name;
if ( name == type.Name )
{
var a = this.GetType().GetProperty(name) as T;
return a;
}
}
return null;
}
The objective is to return the generic type T. First I get the properties of the class, and then I loop over the properties in hopes of finding a property name which has the same name as the type T.
This works okay in my case because the properties are all of the form Interface<FooRepository> FooRepository { get; set; } so I need only compare the two.
This method is inside a class. The problem is that a will change to null immediately after the statement as T. What can be done?
If you want the value of the property you could try using the GetValue method and replace this:
var a = this.GetType().GetProperty(name) as T;
with this:
var a = property.GetValue(this) as T;
Also it is not quite clear what exactly is the purpose of such method but this condition here looks shaky:
if (name == type.Name)
The name of the property should equal the name of the generic type parameter. Is it really what is needed here?
GetProperty method will always return ProprtyInfo type so unless T is PropertyInfo a will be always null.

a function to set property values for several types of classes

I need a function with following signature in C# 4.0, I am lost where to start :
public static object SetStringPropertiesOnly(object obj)
{
//iterate all properties of obj
//if the type of the property is string,
//return obj
}
and eventually I want to use this function for my several objects derived from different classes:
myClass1 obj1 = new myClass1 ();
myClass2 obj2 = new myClass2 ();
.....
.....
obj1 = SetStringPropertiesOnly(obj1);
obj2 = SetStringPropertiesOnly(obj2);
So the type of the objects are dynamic here.
Is such a method possible?.
Thanks.
public static object SetStringPropertiesOnly(object obj)
{
//Get a list of properties where the declaring type is string
var stringProps = obj.GetType().GetProperties().Where(x => x.PropertyType == typeof(string)).ToArray();
foreach (var stringProp in stringProps)
{
// If this property exposes a setter...
if (stringProp.SetMethod != null)
{
//Do what you need to do
stringProp.SetValue(obj, "value", null);
}
}
//What do you want to return?
return obj;
}
Consider changing your method signature to accept a value parameter and also change object obj to be ref, you don't need to return your object then.
I suppose you want to return the object itself.
However you should understand that the original object will also be changed.
public static object SetStringPropertiesOnly(object obj)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, "Value");
}
return obj;
}
My approach would be to make an extension method and return void, since the object would be changed. I also would add the wished string as a parameter.
public static void SetStringProperties(this object obj, string value)
{
var properties = obj.GetType().GetProperties();
var strings = properties.Where(p=>p.PropertyType == typeof(string);
foreach(PropertyInfo property in strings)
{
property.SetValue(obj, value);
}
return obj;
}
You can call the extension method like this:
obj.SetStringProperties("All strings will have this value");
By the way, the fact that you need to do this might be considered a "bad smelling code". Reconsider this design if you can.
Aint hard using reflection. And we can also do it as object extension (looks cute when you use it):
public static class ObjectExtensions
{
public static T SetStringPropertiesOnly<T>(this T obj) where T : class
{
var fields = obj.GetType().GetProperties();
foreach (var field in fields)
{
if (field.PropertyType == typeof (string))
{
field.SetValue(obj, "blablalba", null); //set value or do w/e your want
}
}
return obj;
}
}
and usage:
var obj = someObject.SetStringPropertiesOnly();
You could use a common interface, something in the lines of "IBulkStringEditable". The interface should contain a method "void SetStrings()".
Then all your classes have to implement this interface and the SetStrings method, where every class has different contents for SetStrings, depending on the string properties it has and the values you want them to have.
Then modify the SetStringPropertiesOnly function in this manner:
public static IBulkStringEditable SetStringPropertiesOnly(IBulkStringEditable obj)
{
obj.SetStrings();
return obj;
}
simply u can use dynamic in ur method parameter signature like that--->
public static object SetStringPropertiesOnly(dynamic obj)
{
// proceed
}

C# - Get the item type for a generic list

What would be the best way of getting the type of items a generic list contains? It's easy enough to grab the first item in the collection and call .GetType(), but I can't always be sure there will be an item in the collection.
Hope that makes sense.
Thanks,
Sonny
You could use the Type.GetGenericArguments method for this purpose.
List<Foo> myList = ...
Type myListElementType = myList.GetType().GetGenericArguments().Single();
For a more robust approach:
public static Type GetListType(object someList)
{
if (someList == null)
throw new ArgumentNullException("someList");
var type = someList.GetType();
if (!type.IsGenericType || type.GetGenericTypeDefinition() != typeof(List<>))
throw new ArgumentException("Type must be List<>, but was " + type.FullName, "someList");
return type.GetGenericArguments()[0];
}
But if your variable is typed List<T> then you can just use typeof(T). For example:
public static Type GetListType<T>(List<T> someList)
{
return typeof(T);
}
Note that you don't really even need the someList parameter. This method is just an example for how you could use typeof if you are already in a generic method. You only need to use the reflection approach if you don't have access to the T token (the list is stored in a non-generic-typed variable, such as one typed IList, object, etc.).
list.GetType().GetGenericArguments()[0]
Here's another way which works for non-generic collections, too:
static Type GetItemType(Type collectionType)
{
return collectionType.GetMethod("get_Item").ReturnType;
}
That is, get the return type of foo[x], where foo is of the specified type.
Examples:
// Generic type; prints System.Int32
Console.WriteLine(GetItemType(typeof(List<int>)));
// Non-generic type; prints System.String
Console.WriteLine(GetItemType(typeof(System.Collections.Specialized.StringCollection)));
The GetItemType method above has a couple issues, though:
It throws a NullReferenceException if the type has no indexing operator.
It throws an AmbiguousMatchException if the type has multiple overloads for the indexing operator (e.g. this[string] and this[int]).
Here is a more refined version:
public static Type GetItemType(this Type collectionType)
{
var types =
(from method in collectionType.GetMethods()
where method.Name == "get_Item"
select method.ReturnType
).Distinct().ToArray();
if (types.Length == 0)
return null;
if (types.Length != 1)
throw new Exception(string.Format("{0} has multiple item types", collectionType.FullName));
return types[0];
}
What about this, its all static (e.g. no instances required), and fast (no loops, no usage of linq), and it is simple :) these work for collections:
[System.Diagnostics.DebuggerHidden]
public static Type GetIndexedType(this ICollection poICollection)
{
PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetProperty("Item");
return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
}
[System.Diagnostics.DebuggerHidden]
public static Type GetEnumeratedType(this ICollection poICollection)
{
PropertyInfo oPropertyInfo = poICollection == null ? null : poICollection.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
}
And a few simple unit tests:
[Test]
public void GetIndexedType()
{
Assert.AreEqual(null, ((ICollection)null).GetIndexedType());
Assert.AreEqual(typeof(int), (new List<int>()).GetIndexedType());
Assert.AreEqual(typeof(bool), (new SortedList<string, bool>()).GetIndexedType());
}
[Test]
public void GetEnumeratedType()
{
Assert.AreEqual(null, ((ICollection)null).GetEnumeratedType());
Assert.AreEqual(typeof(int), (new List<int>()).GetEnumeratedType());
Assert.AreEqual(typeof(KeyValuePair<string, bool>), (new SortedList<string, bool>()).GetEnumeratedType());
}
Notice the fact that there are two ways to look at this, one type may be returned by the indexer and an other type may be returned by the enumerator. The unit test do show both.
Have fun,
Frans.
P.s. For enumerables:
[System.Diagnostics.DebuggerHidden]
public static Type GetEnumeratedType(this System.Collections.IEnumerable poIEnumerable)
{
PropertyInfo oPropertyInfo = poIEnumerable == null ? null : poIEnumerable.GetType().GetMethod("GetEnumerator").ReturnType.GetProperty("Current");
return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
}
And for enumerator:
[System.Diagnostics.DebuggerHidden]
public static Type GetEnumeratedType(this System.Collections.IEnumerator poIEnumerator)
{
PropertyInfo oPropertyInfo = poIEnumerator == null ? null : poIEnumerator.GetType().GetProperty("Current");
return oPropertyInfo == null ? null : oPropertyInfo.PropertyType;
}
public Type GetType(IEnumerable<object> resultList)
{
return resultList.GetType().GetElementType();
}
Old question new method with dynamic
void Foo(){
Type type GetTypeT(data as dynamic);
}
private static Type GetTypeT<T>(IEnumerable<T> data)
{
return typeof(T);
}
Public Shared Function ListItemType(ListType As System.Type) As System.Type
If Not ListType.IsGenericType Then
If ListType.BaseType IsNot Nothing AndAlso ListType.BaseType.IsGenericType Then
Return ListItemType(ListType.BaseType)
End If
Else
Return ListType.GetGenericArguments.Single
End If
End Function
Here is a solution that also works with derived classes.
Because with this class :
public class SubList : List<int>
{ }
If you call : subList.GetType().GetGenericArguments().Single()
It will throws a System.InvalidOperationException
With this method it works for derived classes :
public Type GetListItemType<T>(List<T> list)
{
Type type = list.GetType();
while (type != typeof(List<T>))
type = type.BaseType;
return type.GetGenericArguments().Single();
}
var list = new List<int>();
var subList = new SubList();
Console.WriteLine(GetListItemType(list)); // System.Int32
Console.WriteLine(GetListItemType(subList)); // System.Int32

Is it possible to use a c# object initializer with a factory method?

I have a class with a static factory method on it. I want to call the factory to retrieve an instance of the class, and then do additional initialization, preferablly via c# object initializer syntax :
MyClass instance = MyClass.FactoryCreate()
{
someProperty = someValue;
}
vs
MyClass instance = MyClass.FactoryCreate();
instance.someProperty = someValue;
No. Alternatively you could accept a lambda as an argument, which also gives you full control in which part of the "creation" process will be called. This way you can call it like:
MyClass instance = MyClass.FactoryCreate(c=>
{
c.SomeProperty = something;
c.AnotherProperty = somethingElse;
});
The create would look similar to:
public static MyClass FactoryCreate(Action<MyClass> initalizer)
{
MyClass myClass = new MyClass();
//do stuff
initializer( myClass );
//do more stuff
return myClass;
}
Another option is to return a builder instead (with an implicit cast operator to MyClass). Which you would call like:
MyClass instance = MyClass.FactoryCreate()
.WithSomeProperty(something)
.WithAnotherProperty(somethingElse);
Check this for the builder
Both of these versions are checked at compile time and have full intellisense support.
A third option that requires a default constructor:
//used like:
var data = MyClass.FactoryCreate(() => new Data
{
Desc = "something",
Id = 1
});
//Implemented as:
public static MyClass FactoryCreate(Expression<Func<MyClass>> initializer)
{
var myclass = new MyClass();
ApplyInitializer(myclass, (MemberInitExpression)initializer.Body);
return myclass ;
}
//using this:
static void ApplyInitializer(object instance, MemberInitExpression initalizer)
{
foreach (var bind in initalizer.Bindings.Cast<MemberAssignment>())
{
var prop = (PropertyInfo)bind.Member;
var value = ((ConstantExpression)bind.Expression).Value;
prop.SetValue(instance, value, null);
}
}
Its a middle between checked at compile time and not checked. It does need some work, as it is forcing constant expression on the assignments. I think that anything else are variations of the approaches already in the answers. Remember that you can also use the normal assignments, consider if you really need any of this.
Yes. You can use object initializer for already created instance with the following trick. You should create a simple object wrapper:
public struct ObjectIniter<TObject>
{
public ObjectIniter(TObject obj)
{
Obj = obj;
}
public TObject Obj { get; }
}
And now you can use it like this to initialize your objects:
new ObjectIniter<MyClass>(existingInstance)
{
Obj =
{
//Object initializer of MyClass:
Property1 = value1,
Property2 = value2,
//...
}
};
P.S. Related discussion in dotnet repository:
https://github.com/dotnet/csharplang/issues/803
You can use an extension method such as the following:
namespace Utility.Extensions
{
public static class Generic
{
/// <summary>
/// Initialize instance.
/// </summary>
public static T Initialize<T>(this T instance, Action<T> initializer)
{
initializer(instance);
return instance;
}
}
}
You would call it as follows:
using Utility.Extensions;
// ...
var result = MyClass.FactoryCreate()
.Initialize(x =>
{
x.someProperty = someValue;
x.someProperty2 = someValue2;
});
+1 on "No".
Here's an alternative to the anonymous object way:
var instance = MyClass.FactoryCreate(
SomeProperty => "Some value",
OtherProperty => "Other value");
In this case FactoryCreate() would be something like:
public static MyClass FactoryCreate(params Func<object, object>[] initializers)
{
var result = new MyClass();
foreach (var init in initializers)
{
var name = init.Method.GetParameters()[0].Name;
var value = init(null);
typeof(MyClass)
.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)
.SetValue(result, value, null);
}
return result;
}
No, the object initializer can only be used on a call to "new" with the constructor. One option might be to add some additional args to your factory method, to set those values at object creation inside the factory.
MyClass instance = MyClass.FactoryCreate(int someValue, string otherValue);
Like everyone said, no.
A lambda as an argument has already been suggested.
A more elegant approach would be to accept an anonymous and set the properties according to the object. i.e.
MyClass instance = MyClass.FactoryCreate(new {
SomeProperty = someValue,
OtherProperty = otherValue
});
That would be much slower though, since the object would have to be reflected on for all the properties.
No, that's something you can only do 'inline'. All the factory function can do for you is to return a reference.

Categories

Resources