C# How to init property (without setter) by reflection - c#

Task:
Serialize a list of objects into a byte[] using protobuf.
Without reflection all is good
.proto
message MyObject{
int32 id = 1;
int32 value = 2;
}
message MyObjects {
repeated MyObject objects = 1;
}
.cs
public static byte[] ToByteArray(List<MyObject> obj) {
var objects = new MyObjects {
Objects = {obj}
};
return objects.ToByteArray();
}
Since I need to serialize many different types in this way, I want to write a universal method using reflection.
Problem:
Protobuf itself generates entities and properties for them, but it does not create a setter for RepeatedField, which means that I can not set the value using GetProperty("Objects")?.SetValue(objects, obj). System.ArgumentException: Set Method not found for 'Objects'
.cs (protobuf generated)
public pbc::RepeatedField<global::Test.MyObject> Objects {
get { return objects_; }
}
.cs
public static byte[] ToByteArray<T, E>(List<T> obj) where T : IMessage where E : IMessage {
var objects = Activator.CreateInstance<E>();
objects.GetType().GetProperty("Objects")?.SetValue(objects, obj);
return objects.ToByteArray();
}
Question:
How to use reflection to set values ​​for a property during object creation, just as I do it without reflection?
How to write this "new MyObjects {Objects = {obj}}; (where obj: IEnumerable)" using reflection
Various conclusions:
I noticed that filling properties that do not have a setter is only possible for collections and only when creating an object.
Most likely I need an alternative way to instantiate the class. Activator.CreateInstance() is not fulfilling my task.

When we do this:
var x = new Thing
{
SomeProperty = "x",
SomeOtherProperty = 1
}
we aren't setting the values during object creation. This is the equivalent of:
var x = new Thing();
x.SomeProperty = "x";
x.SomeOtherProperty = 1;
In both cases the properties are set after the object is instantiated by setting their properties. An easy way to verify this is to try using the syntax from the first example to set a property that doesn't have a setter. It won't compile. You'll see this error:
Property or indexer 'Thing.SomeProperty' cannot be assigned to -- it is read-only.
In other words, the object, as defined, does not provide a way to set the Objects property.
The question is whether you really need to set the property. Quite likely you only need to add items to the collection.
Doing this with reflection is still really ugly. I don't recommend this at all. This is a crude version. It can fail at runtime for all sorts of reasons.
public static byte[] ToByteArray<T, E>(List<T> itemsToAdd) where T : IMessage where E : IMessage
{
// create an instance of the object
var created = Activator.CreateInstance<E>();
// Find the "Objects" property. It could be null. It could be the wrong type.
var objectsProperty = typeof(E).GetProperty("Objects");
// Get the value of the objects property. Hopefully it's the type you expect it to be.
var collection = objectsProperty.GetValue(created);
// Get the Add method. This might also be null if the method doesn't exist.
var addMethod = collection.GetType().GetMethod("Add");
// invoke the Add method for each item in the collection
foreach(var itemToAdd in itemsToAdd)
{
addMethod.Invoke(collection, new object[] { itemToAdd });
}
return created.ToByteArray();
}
Unless we're forced to, we really don't want to do that. I don't know what your IMessage type look like.
Does it have the Objects property?
In that case you could just do this:
public static byte[] ToByteArray<T, E>(List<T> itemsToAdd)
where T : IMessage
where E : IMessage, new()
{
var created = new E();
foreach (var itemToAdd in itemsToAdd)
{
created.Objects.Add(itemToAdd);
}
// or skip the foreach and just do
// created.Objects.AddRange(itemToAdd);
return created.ToByteArray();
}
I'm guessing about whether your interface has that property. But if at all possible, you're better off doing this with generic constraints than with reflection. This way your code is checked for most possible errors when it compiles, as opposed to running it and having it blow up because this or that property or method doesn't exist, is wrong, etc.
The new() constraint simply means that E must be a type with a default constructor, which means that in order for it to compile, E must be a type you can create without passing anything to the constructor. (Without that constraint, new E() won't compile.)
Without that constraint even Activator.CreateInstance might fail because the the type might not have a default constructor.

Scott's answer solves the problem, but I used a shortened solution in the end
private static byte[] ToByteArray<T, E>(IEnumerable<T> obj) where T : IMessage where E : IMessage, new() {
var objects = new E();
(objects.GetType().GetProperty("Objects")?.GetValue(objects) as RepeatedField<T>)?.AddRange(obj);
return objects.ToByteArray();
}

Related

C# dictionary lookup using derived class

I think this could be a common question but I failed to find any post about it.
I'm writing some pseudo code below. If you want to compile the code, please just ignore this post.
So say two classes: one base class and one child class. NOTE: both classes have override Equals() and GetHashCode() function to ensure equality with same property.
public class A // A has a string property of name
public class B:A // B has a string property of title
var a = new A{name = "bob"};
var b = new B{name = "bob", title = "em"};
Some code have a dictionary based on A
var dict = new Dictionary<A>();
Doing some adding stuff, for instance,
dict.Add(a);
However, the lookup function will raise KeyNotFoundException if i use a derived class searching with/o type cast
dict[b];
Dictionary will calculate the hashcode of B instead of A and raised the exception according to that.
A simple and awkward solution is to create a new instance of A based on B's property.
dict[new A{name = b.name}];
I wonder if there is any better solution?
Try creating an EqualityComparer, and pass an instance of it in the constructor of the dictionary.
class AEqualityComparer : IEqualityComparer<A>
{
public bool Equals(A x, A y)
{
return x.Equals(y);
}
public int GetHashCode(A obj)
{
return obj.GetHashCode();
}
}
var dict = new Dictionary<A, object>(new AEqualityComparer());
You're confusing storing objects in a list, with the key of a dictionary. If you use objects as a key, you need to supply a reference to the same object - not just one with the same properties.
If you do this:
dict.Add(new A{name = "bob"}, someData);
and then do this
var result = dict[new A{name = "bob"}];
you'll get 'key not found' because the two new As are different objects.

Is it possible to get the original type of a list when all you have is a "WhereEnumerableIterator" of that list?

It may be simple but nevertheless it has caused us a bit of headache over the past few hours.
Long story short: We need to fix a memory leak and the way to do it is to return the original list without creating a new instance of MyBindingList if ToBindingList is invoked on a list that is already of the type MyBindingList
MyBindingList inherits System.ComponentModel.BindingList
How would you write the extension method ToBindingList() allowing this test passes?
[TestMethod]
public void FooBar()
{
var SUT = new MyBindingList<FooBar>
{
new FooBar{Name = "AAA"},
new FooBar{Name = "BBB"},
};
var filteredList = SUT.Where(x => x.Name == "AAA").ToBindingList();
Assert.AreEqual(1, filteredList.Count);
Assert.AreEqual(true, ReferenceEquals(filteredList, SUT));
}
private class FooBar
{
public string Name { get; set; }
}
MyBindingList constructor goes like this
public class MyBindingList<T> : BindingList<T>, IEntityChanged
{
public MyBindingList(IList<T> list) : base(list) { }
//...
}
The problem we encounter is that the extension method operates on an iterator (the Where-clause) so we have no way of comparing the type informatoin of the two lists. We wrote the following extension method and then got wiser - and stuck:
public static MyBindingList<T> ToBindingList<T>(this IEnumerable<T> container)
{
var returnVal = container as MyBindingList<T>;
if (returnVal != null)
return returnVal;
return new MyBindingList<T>(container.ToList());
}
Can anybody help us here to a viable solution or explain why the compiler will never allow us to do something like this?
Thanks in advance
BindingList<T> (and more recently, ObservableCollection<T>) are just not for this purpose. They meant to wrap a 'final' result of a collection provided by your ViewModel or whatever underlying layer. If you need to filter the list you have basically two options:*
Return a new instance of the of the BindingList<T> (wrapping simple collections instead of another binding list) and rebind your view.
Handle the 'filtering' by removing the items from the binding list and just allow the view to update accordingly as it processes the notifications of the list change (after all that's why one uses an observable collection such as BindingList<T>).
*Remark: If your View uses WinForms technology, you can use the BindingSource type in the form (its DataSource can be your binding list), which also implements IBindingList. It has a Filter property, which is a string and can accept fancy expressions but actually I would not use this property in practice.
Looking at the source code, you can do this using Reflection:
var data = new List<int>();
var iterator = data.Where(x => 1 == 1);
var type = iterator.GetType();
var sourceField = type.GetField("source", System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance);
Console.WriteLine(sourceField.FieldType);
Which prints:
System.Collections.Generic.List`1[System.Int32]
You can test this on this fiddle.
So you could do something like this to get the value:
public static List<T> GetOriginalList<T>(this IEnumerable<T> whereSource)
{
var type = whereSource.GetType();
var sourceField = type.GetField("source",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.GetField);
return sourceField as List<T>;
}
public static MyBindingList<T> ToBindingList<T>(this IEnumerable<T> container)
{
var returnVal = container as MyBindingList<T>;
if (returnVal != null)
return returnVal;
return new MyBindingList<T>(container.GetOriginalList<T>());
}
Definitely possible, but hacky. Use reflection to check if the type is a nested type whose parent is System.Linq.Enumerable. If so, use reflection to get the value of the private 'source' instance field. That is the original source of the Where. This should work for all Enumerable methods, but I recommend you do this in a loop until you've reached the root source to support more complex querying. I also recommend caching reflection results in a static place. Fair warning though - there's no guarantee that 'source' will continue to be the name of the private field in upcoming releases. To rely on it means you need to re-test this for each and every .NET framework release you intend to run it on. It might just stop working one day.

How to fix null subclasses instances with reflection

I have a main instance storing various subclasses instances with options inside.
Class MainClass
{
public bool b;
public int i;
public List l = new List();
Class SubClass1
{
...
}
public SubClass1 sub1 = new SubClass1();
Class SubClass2
{
...
}
public SubClass2 sub2 = new SubClass2();
}
now, when starting all class are correctly instatiated, then some options are set, and the result is serialized.
The problem arises when (for various reasons) I have to change name of the instances.
E.g. SubClass2---->SubClassB
therefore when de-serializing SubClassB is obviously null.
So I have to fix this drawback and I have tought about reflection.
Something like [pseudocode]
foreach(var subclass in MainClass)
{
if(subclass is null)
{
Type subClassType = typeof(subclass);
subclass = new subClassType();
}
}
Thank you in advance for any help.
---ADD for completeness the solution from thehennny's hint---
private void CheckAndFixNullInstances()
{
easyRunData.OptionsReport = null;
Type fieldsType = typeof(EasyRunBinSerializableData);
FieldInfo[] fields = fieldsType.GetFields(BindingFlags.Public | BindingFlags.Instance);
for (int i = 0; i < fields.Length; i++)
{
string str = fields[i].Name + " " + fields[i].GetValue(easyRunData);
if (fields[i].GetValue(easyRunData) == null)
{
string strFieldType = fields[i].FieldType.AssemblyQualifiedName;
Type t = Type.GetType(strFieldType);
object item;
item = Activator.CreateInstance(t);
fields[i].SetValue(easyRunData, item);
}
}
}
I am not familiar with the xml deserialization process, but what you basically want is to loop over all fields of a particular object and fill all null fields with a new object of the fields type.
To get all fields of the type you have to use a suitable Type.GetFields overload.
Then you can loop over the FieldInfo objects you got and call the FieldInfo.GetValue Method.
After doing the null check you can then create a new object with the Activator.CreateInstance Method by passing the FieldInfo.FieldType Property as parameter and store it in the field using the FieldInfo.SetValue Method.
The above won't work as you cannot get any type information from a null object. Essentially when you serialise the object you would want to store the fully qualified name of the class you expect. Then when you deserialise it out you can read that value. If the object is "null", you can create an instance of the fully qualified type.
NB: Note "null" in quotes because here "null" is used to semantically mean something which is not there and not necessarily a null object.
NBB: I have solved exactly that problem in a Github project I have which you are welcome to use (https://github.com/ruskindantra/extensions/blob/master/RuskinDantra.Extensions/DataStructures/XmlSerializableInterfaceList.cs).

Check if two variables are of the same when the type is dynamic and both variables are the derivatives of same base class

Is it possible to check if the list contains an object of given (but dynamic) type, derrived from same basic abstract class?
The main problem is not about the list, but about comparing types itself.
In single variables and static variables, it's easy:
if(someVariable is int)
Checking the list with static type is also easy, like:
SomeList.OfType<int>().Any()
or
(from _Object in SomeList.OfType<int> where _Object is int select _Object).Count() == 0
but I cant't handle it if the type I want to check is dynamic, f.e. passed as method parameter:
abstract class BasicClass;
class DerivativeOne : BasicClass { }
class DerivativeTwo : BasicClass { }
// in main:
List<BasicClass> _List = new List<BasicClass>();
DerivativeOne a = new DerivativeOne();
DerivativeTwo b = new DerivativeTwo();
DerivativeOne c = new DerivativeOne();
if(!CheckIfTypeExistsInList(a, _List)
{
_List.Add(a);
}
if(!CheckIfTypeExistsInList(b, _List)
{
_List.Add(b);
}
if(!CheckIfTypeExistsInList(c, _List)
{
_List.Add(c); // this is what I don't want to happen,
// because I already have one object of type DerivativeOne in my list.
}
// the function:
bool CheckIfTypeExistsInList(BasicClass pObject, List<BasicClass> pList)
{
/// few attempts:
pList.OfType<(pObject.GetType()>().Any(); // attempt one, error
return (from _Object in SomeList.OfType<(pObject.GetType())> where _Object is int select _Object).Count() == 0; // attempt two, error
}
PS. I am aware that the code doesn't look neat, but I tried to show just the problem itself, skipping extra logic and stuff.
PS2. I am aware that the solution to the problem would be just to put some attribute to BasicClass and make each derivative to have unique value of the attribute, but still - I'm not looking for another route to solve the problem, I'm just interested if it's possible to do it "this" way.
When the type is known only at runtime, you cannot use it in a generic without using reflection. However, your task is simpler than that - you can use type equality to achieve the results that you want:
Type targetType = pObject.GetType();
if (SomeList.Any(o => targetType.Equals(o.GetType()))) {
...
}

How can I use custom-attributes in C# to replace switches in switches?

I have a factory method that returns the correct sub class depending on three enum values.
One way to do is, would be to use switches in switches in switches. Obviously, I don't like that option very much.
I thought that another option would be to use attributes in C#. Every sub class would have an attribute with that 3 enum values and in the factory I would only have to get the class that has the same enum values corresponding to the enum values i have in the factory.
However, I am quite new to attributes and I did not find any suitable solution in the web. If anyone, could just give me some hints or some lines of code, I really would appreciate that!
First of all, declare your attribute and add it to your classes.
enum MyEnum
{
Undefined,
Set,
Reset
}
class MyEnumAttribute : Attribute
{
public MyEnumAttribute(MyEnum value)
{
Value = value;
}
public MyEnum Value { get; private set; }
}
[MyEnum(MyEnum.Reset)]
class ResetClass
{
}
[MyEnum(MyEnum.Set)]
class SetClass
{
}
[MyEnum(MyEnum.Undefined)]
class UndefinedClass
{
}
Then, you can use this code to create a dictionary with your enums and types, and dynamically create a type.
//Populate a dictionary with Reflection
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new {t, Attribute = t.GetCustomAttribute(typeof (MyEnumAttribute))}).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value, e => e.t);
//Assume that you dynamically want an instance of ResetClass
var wanted = MyEnum.Reset;
var instance = Activator.CreateInstance(dictionary[wanted]);
//The biggest downside is that instance will be of type object.
//My solution in this case was making each of those classes implement
//an interface or derive from a base class, so that their signatures
//would remain the same, but their behaviors would differ.
As you can probably notice, calling Activator.CreateInstance is not performant. Therefore, if you want to improve the performance a little bit, you can change the dictionary to Dictionary<MyEnum,Func<object>> and instead of adding types as values you would add functions wrapping the constructor of each of your classes and returning them as objects.
EDIT: I'm adding a ConstructorFactory class, adapted from this page.
static class ConstructorFactory
{
static ObjectActivator<T> GetActivator<T>(ConstructorInfo ctor)
{
var paramsInfo = ctor.GetParameters();
var param = Expression.Parameter(typeof(object[]), "args");
var argsExp = new Expression[paramsInfo.Length];
for (var i = 0; i < paramsInfo.Length; i++)
{
Expression index = Expression.Constant(i);
var paramType = paramsInfo[i].ParameterType;
Expression paramAccessorExp = Expression.ArrayIndex(param, index);
Expression paramCastExp = Expression.Convert(paramAccessorExp, paramType);
argsExp[i] = paramCastExp;
}
var newExp = Expression.New(ctor, argsExp);
var lambda = Expression.Lambda(typeof(ObjectActivator<T>), newExp, param);
var compiled = (ObjectActivator<T>)lambda.Compile();
return compiled;
}
public static Func<T> Create<T>(Type destType)
{
var ctor = destType.GetConstructors(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance).First();
Func<ConstructorInfo, object> activatorMethod = GetActivator<Type>;
var method = typeof(ConstructorFactory).GetMethod(activatorMethod.Method.Name, BindingFlags.Static | BindingFlags.NonPublic);
var generic = method.MakeGenericMethod(destType);
dynamic activator = generic.Invoke(null, new object[] { ctor });
return () => activator();
}
delegate T ObjectActivator<out T>(params object[] args);
}
You can use it as an alternative to Activator.CreateInstance, it provides greater performance if the result is cached.
var dictionary = Assembly.GetExecutingAssembly().GetTypes().
Select(t => new { t, Attribute = t.GetCustomAttribute(typeof(MyEnumAttribute)) }).
Where(e => e.Attribute != null).
ToDictionary(e => (e.Attribute as MyEnumAttribute).Value,
e => ConstructorFactory.Create<object>(e.t));
var wanted = MyEnum.Reset;
var instance = dictionary[wanted]();
Have a look at this article: Creating Custom Attributes. You can then use reflection (for instance GetCustomAttributes) to get the attributes and their values.
Hope this helps
[AttributeUsage(AttributeTargets.Class)]
public class SampleClass : Attribute {
public SampleClass() : base() { }
public SampleClass(YourEnum attributeValue) : this() { MyAttributeProperty = attributeValue; }
public YourEnum MyAttributeProperty { get; set; }
}
public enum YourEnum { Value1, Value2, Value3 }
[SampleClass(YourEnum.Value1)]
public class ExampleValue1Class { }
public class LoadOnlyClassesWithEnumValue1 {
public LoadOnlyClassesWithEnumValue1() {
Type[] allTypes = Assembly.GetExecutingAssembly().GetExportedTypes();
foreach (var type in allTypes) {
if (type.GetCustomAttributes(typeof(SampleClass), false).Length > 0) {
SampleClass theAttribute = type.GetCustomAttributes(typeof(SampleClass), false).Single() as SampleClass;
// this type is using SampleClass - I use .Single() cause I don't expect multiple SampleClass attributes, change ths if you want
// specify true instead of false to get base class attributes as well - i.e. ExampleValue1Class inherits from something else which has a SampleClass attribute
switch (theAttribute.MyAttributeProperty) {
case YourEnum.Value1:
// Do whatever
break;
case YourEnum.Value2:
// you want
break;
case YourEnum.Value3:
default:
// in your switch here
// You'll find the ExampleValue1Class object should hit the Value1 switch
break;
}
}
}
}
}
This way you can specify your enum as a parameter to the attribute. In essence, this is a very simple and lightweight DI container.
I'd suggest for anything more complex, to use something like StructureMap or NInject.
Another solution would be to use Dependency Injection (DI) container. For instance using Unity DI you can:
// Register a named type mapping
myContainer.RegisterType<IMyObject, MyRealObject1>(MyEnum.Value1.ToString());
myContainer.RegisterType<IMyObject, MyRealObject2>(MyEnum.Value2.ToString());
myContainer.RegisterType<IMyObject, MyRealObject3>(MyEnum.Value3.ToString());
// Following code will return a new instance of MyRealObject1
var mySubclass = myContainer.Resolve<IMyObject>(myEnum.Value1.ToString());
Examples on using Unity:
Implementing the Microsoft Unity (Dependency Injection) Design Pattern
Of course you can use any DI container (Castle Windsor, StructureMap, Ninject. Here is a list some of the available .NET DI containers List of .NET Dependency Injection Containers (IOC)
It is possible to use attributes to hold the information, but ultimately the decision process will still have to be made and will likely not be much different; just with the added complexity of the attributes. The nature of the decision remains the same regardless of where you get the information to make the decision, from the existing three enumerations or from attributes.
It may prove more fruitful to look for a way to combine the three enumerations.
Enums can be any integral type, so the easiest way to eliminate nested (and redundant) switches is to combine the enumerations together. This is easiest if the enumeration is a collection of flag values. That is, each value of the enumeration has the value of a single bit in a binary string (1 for the first bit, 2 for the second bit, 4 for the third, 8, 16 and so on).
Provided the values of each of the enumerations can be joined together it reduces the selection process to a single switch statement. This may be best done by concatenating, multiplying or adding the enumeration values -- but how they are joined together depends on the enumerations, and without knowing more details it is hard to provide more definite direction.

Categories

Resources