Why does this cloning not work? - c#

I'm trying to clone instances of a derived class, but somehow it doesn't work well. The cloning method is:
public static T CloneFieldsAndProperties<T>(T input)
{
T result = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] listOfProps = typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance);
FieldInfo[] listOfFields = typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.CreateInstance);
foreach (PropertyInfo prop in listOfProps) prop.SetValue(result, prop.GetValue(input, null), null);
foreach (FieldInfo field in listOfFields) field.SetValue(result, field.GetValue(input));
return result;
}
As you can see, I added many BindingFlags because it wasn't working. But to no avail.
It does work in a simple case:
MyclassA1 a1 = new MyclassA1();
MyclassA a = CloneFieldsAndProperties(a1);
if (a is MyclassA1) Text = "Works";
Where:
class MyclassA
{
public int i;
}
class MyclassA1 : MyclassA
{
public int i1;
}
But in my real program it doesn't. The real program's classes' declarations are long so I'm not posting them here. What might be the problem?

I had the same issue a long time ago. The only real solution for me, after lots of googling, was to serialize and deserialize it. It's not a bad solution and you lose only a little bit of performance, just do it like this:
Add this tag to your class:
[Serializable()]
public class a
{
}
And then you can create a function like this:
public object Clone()
{
IO.MemoryStream mem = new IO.MemoryStream();
System.Runtime.Serialization.Formatters.Binary.BinaryFormatter form = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
form.Serialize(mem, this);
mem.Position = 0;
return form.Deserialize(mem);
}

If you need a shallow clone, simply use Object.MemberwiseClone. If you need a deep clone, serialize and then deserialize your object (e.g. using BinaryFormatter or DataContractSerializer). This would take care of issues such as cycles and cross references.

This will work and may be faster than the serialization method:
Code:
using System;
namespace Cloning
{
class Program
{
static void Main(string[] args)
{
Derived d = new Derived() { property = 1, field = 2, derivedProperty = 3, derivedField = 4 };
Base b = new Derived(d);
// Change things in the derived class.
d.property = 5;
d.field = 6;
d.derivedProperty = 7;
d.derivedField = 8;
// Output the copy so you know it's not shallow.
Console.WriteLine((b as Derived).property);
Console.WriteLine((b as Derived).field);
Console.WriteLine((b as Derived).derivedProperty);
Console.WriteLine((b as Derived).derivedField);
Console.ReadLine();
}
class Base
{
public int property { get; set; }
public int field;
}
class Derived : Base
{
public Derived() { }
public Derived(Derived d)
{
// Perform the deep copy here.
// Using reflection should work, but explicitly stating them definitely
// will, and it's not like it's not all known until runtime.
this.property = d.property;
this.field = d.field;
this.derivedProperty = d.derivedProperty;
this.derivedField = d.derivedField;
}
public int derivedProperty { get; set; }
public int derivedField;
}
}
}
Test:
http://goo.gl/pQnAL
Output:
1
2
3
4
Comments:
I would really imagine that this would work in more than just a trivial case but perhaps not:
public static T CloneFieldsAndProperties<T>(T input)
{
T result = (T)Activator.CreateInstance(input.GetType());
PropertyInfo[] properties = input.GetType().GetProperties();
FieldInfo[] fields = input.GetType().GetFields();
foreach (PropertyInfo property in properties)
property.SetValue(result, property.GetValue(input, null), null);
foreach (FieldInfo field in fields)
field.SetValue(result, field.GetValue(input));
return result;
}

Related

Get with Reflection fields that are not generated by the compiler

Recently I was writing a method to construct a graph with the dependencies between classes using Reflection and found the following problem. My method analyzes the return type of property, generic arguments of class definition and instance fields of those classes.
For inspection of instance fields of class I use the following method.
public static IEnumerable<FieldInfo> GetFields(Type classType)
{
return classType
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
To test it, I write the following class definition:
static void Main(string[] args)
{
foreach (var fieldInfo in GetFields(typeof(A)))
Console.WriteLine(fieldInfo.Name);
Console.ReadKey();
}
class A
{
private ulong? _field1;
public byte PropertyA { get; set; }
public int PropertyB { get; set; }
public bool PropertyC { get; set; }
}
I was in shock for a few seconds, to see the result. It was when I remembered that .NET generates an instance field, Set and Get methods to emulate the properties.
When I inspected with .NET Reflector the library to see the code generated by the compiler, I find the following definition.
class A
{
private ulong? _field1;
[CompilerGenerated]
private Byte <PropertyA>k__BackingField;
[CompilerGenerated]
private Int32 <PropertyB>k__BackingField;
[CompilerGenerated]
private bool <PropertyC>k__BackingField;
}
So I modified the method to exclude the fields with CompilerGenerated attribute and his name match with some property.
public static IEnumerable<FieldInfo> GetFields(Type classType)
{
var regex = new Regex(#"^<(?<PropertyName>\w+)>\w+$");
var fieldInfoes = classType
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var fieldInfo in fieldInfoes)
{
if (fieldInfo.GetCustomAttribute<CompilerGeneratedAttribute>() == null)
yield return fieldInfo;
else
{
var match = regex.Match(fieldInfo.Name);
if (!match.Success)
continue;
var propertyName = match.Groups[#"PropertyName"].Value;
if (classType.GetProperty(propertyName) == null)
yield return fieldInfo;
}
}
}
QUESTIONS
There is some combination of BindingFlags I'm missing for these fields?
There is another way of getting these fields because this code appears to me that is like killing a mosquito with a bazooka?
You can download the complete code here.
You need the fields that are: !field.IsDefined(typeof(CompilerGeneratedAttribute), false)
public static IEnumerable<FieldInfo> GetFields(Type classType)
{
var allFields = classType
.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
var definedFields = from field in allFields
where !field.IsDefined(typeof(CompilerGeneratedAttribute), false)
select field;
return definedFields;
}

List methods and invoke them at runtime

Here's the situation :
I want to create a test application which would be able to retrieve all the class and methods within a dll and allow me to call them at runtime.
What I have is something like this :
Let's say I have those classes :
public static class FirstManagerSingleton
{
public static SecondManager Instance
{
return mInstance; // which is a SecondManager private static object
}
}
public class SecondManager
{
public Service1 service1 {get; private set;}
public Service2 service2 {get; private set;}
...
}
public class Service1
{
public bool Method1()
{
return true;
}
public int Method2()
{
return 1;
}
...
}
public class Service2
{
public bool Method1()
{
return false;
}
public int Method2(int aNumber)
{
return aNumber - 1;
}
...
}
I want to be able to select each "Service" Class, call any method and show its result.
Is it possible to do this using reflection ? If it wasn't of the multiple layers (The 2 managers class) I wouldn't struggle that much. The fact is I need to access the service class through a call which look like this :
FirstManagerSingleton.Instance.Service1.Method1;
So far, I've been able to load the assembly and retrieve almost every methods and print them.
Assembly assembly = Assembly.LoadFrom("assemblyName");
// through each type in the assembly
foreach (Type type in assembly.GetTypes())
{
// Pick up a class
if (type.IsClass == true)
{
MethodInfo[] methodInfo;
Console.WriteLine("Found Class : {0}", type.FullName);
Type inter = type.GetInterface("I" + type.Name, true);
if (inter != null)
{
methodInfo = inter.GetMethods();
foreach (MethodInfo aMethod in test2)
{
Console.WriteLine("\t\tMethods : " + aMethod);
}
}
}
}
From there, I don't really know what to do next to invoke the methods.
By the way, those methods could take some parameters and have some return types.
I'm using the interface to retrieve the methods in order to filter from the methods inherited from another interface.
I hope I was clear enough. Sorry I can't post the real code sample, but I guess it's enough to illustrate the concept.
You should get the classes from the assemblies, then recursively get the property values and execute the methods. Here is some simple code that you should tailor according to your needs:
public void ExecuteAssembly(string anAssemblyName)
{
Assembly assembly = Assembly.LoadFrom(anAssemblyName);
foreach (Type type in assembly.GetTypes())
{
if (type.IsClass)
{
TypeAttributes atts = type.Attributes;
if ((atts & TypeAttributes.Sealed) != 0) // identify the static classes
ExecuteEverything(type);
}
}
}
private void ExecuteEverything(Type type)
{
// get only the public STATIC properties and methods declared in the type (i.e. not inherited)
PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
MethodInfo[] meths = type.GetMethods(BindingFlags.Public | BindingFlags.Static
| BindingFlags.DeclaredOnly);
// execute the methods which aren't property accessors (identified by IsSpecialMethod = true)
foreach (MethodInfo aMeth in meths)
if (!aMeth.IsSpecialName)
Execute(aMeth, type);
// for each property get the value and recursively execute everything
foreach (PropertyInfo aProp in props)
{
object aValue = aProp.GetValue(type, null);
if (aValue != null)
RecursivelyExecuteEverything(aValue);
}
}
private void RecursivelyExecuteEverything(object aValue)
{
Type type = aValue.GetType();
// get only the public INSTANCE properties and methods declared in the type (i.e. not inherited)
PropertyInfo[] props = type.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MethodInfo[] meths = type.GetMethods(BindingFlags.Public | BindingFlags.Instance
| BindingFlags.DeclaredOnly);
// execute the methods which aren't property accessors (identified by IsSpecialMethod = true)
foreach (MethodInfo aMeth in meths)
if (!aMeth.IsSpecialName)
Execute(aMeth, aValue);
// for each property get the value and recursively execute everything
foreach (PropertyInfo aProp in props)
{
object newValue = aProp.GetValue(aValue, null);
if (newValue != null)
RecursivelyExecuteEverything(newValue);
}
}
private void Execute(MethodInfo aMeth, object anObj)
{
// be careful that here you should take care of the parameters.
// this version doesn't work for Method2 in Service2, since it
// requires an int as parameter
aMeth.Invoke(anObj, null);
}

C# use string as a class field name

Sorry if the tile is misleading. What i would like to do is to use a string to get the values from a class. What i have:
class foo
{
public string field1 {get;set;}
public string field2 {get;set;}
}
public void run()
{
//Get all fields in class
List<string> AllRecordFields = new List<string>();
Type t = typeof(foo);
foreach (MemberInfo m in t.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
AllRecordFields.Add(m.Name);
}
foo f = new foo();
foreach(var field in AllRecordFields)
{
//field is a string with the name of the real field in class
f.field = "foobar";
}
}
This a really simple example, so the problem is on the line f.field = "foobar";
The field is a string with a name of the real class field what i want to assignt the value to.
Use PropertyInfo instead of MemberInfo and then SetValue.
public void run()
{
foo f = new foo();
Type t = typeof(foo);
foreach (PropertyInfo info in t.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic))
{
info.SetValue(f, "foobar", new object[0]);
}
}
First of all, it is better to use Properties instead of fields.
Second your fields are private, can't be accessed from outside foo. You need to declare them as public.
For your example you have to use reflection to access those files. But that is slow and it is not very good style. You better use the class directly (with property setter) or us an interface.
Add method into foo class to change all properties
class foo
{
public string field1 {get;set;}
public string field2 { get; set; }
public void SetValueForAllString( string value)
{
var vProperties = this.GetType().GetProperties();
foreach (var vPropertie in vProperties)
{
if (vPropertie.CanWrite
&& vPropertie.PropertyType.IsPublic
&& vPropertie.PropertyType == typeof(String))
{
vPropertie.SetValue(this, value, null);
}
}
}
}
foo f = new foo() { field1 = "field1", field2 = "field2" };
f.SetValueForAllString("foobar");
var field1Value = f.field1; //"foobar"
var field2Value = f.field2; //"foobar"

Create an instance of DirectoryEntry for use in test

I'm attempting to create an instance of a DirectoryEntry so that I can use this to test some code that will be passed a DirectoryEntry. However, despite a lot of trying I can't find a way to instantiate a DE and initialize it's PropertyCollection.
I have the following code which was taken and modified from another answer on SO that was doing the same process but for the SearchResult object. It seems that the Add method has been completely disabled and I can't find a way to call a constructor on PropertyCollection to pass in some properties.
using System.Collections;
using System.DirectoryServices;
using System.Globalization;
using System.Reflection;
using System.Runtime.Serialization;
public static class DirectoryEntryFactory
{
const BindingFlags nonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance;
const BindingFlags publicInstance = BindingFlags.Public | BindingFlags.Instance;
public static DirectoryEntry Construct<T>(T anonInstance)
{
var e = GetUninitializedObject<DirectoryEntry>();
SetPropertiesField(e);
var dictionary = (IDictionary)e.Properties;
var type = typeof(T);
var propertyInfos = type.GetProperties(publicInstance);
foreach (var propertyInfo in propertyInfos)
{
var value = propertyInfo.GetValue(anonInstance, null);
var valueCollection = GetUninitializedObject<PropertyValueCollection>();
var innerList = GetInnerList(valueCollection);
innerList.Add(value);
var lowerKey = propertyInfo.Name.ToLower(CultureInfo.InvariantCulture);
// These both throw exceptions saying you can't add to a PropertyCollection
//(typeof(PropertyCollection)).InvokeMember("System.Collections.IDictionary.Add", nonPublicInstance | BindingFlags.InvokeMethod, null, dictionary, new object[] { propertyInfo.Name, value });
//dictionary.Add(lowerKey, propertyCollection);
}
return e;
}
private static ArrayList GetInnerList(object propertyCollection)
{
var propertyInfo = typeof(PropertyValueCollection).GetProperty("InnerList", nonPublicInstance);
return (ArrayList)propertyInfo.GetValue(propertyCollection, null);
}
private static void SetPropertiesField(DirectoryEntry e)
{
var propertiesField = typeof(DirectoryEntry).GetField("propertyCollection", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
propertiesField.SetValue(e, GetUninitializedObject<PropertyCollection>());
}
private static T GetUninitializedObject<T>()
{
return (T)FormatterServices.GetUninitializedObject(typeof(T));
}
}
usage is intended to be
DirectoryEntry e = DirectoryEntryFactory.Construct(new { attr1 = "Hello", attr2 = "World"});
I'm hoping I've missed something as I'm pretty new to using reflection in anger.
I'm not familiar with DirectoryEntry itself, but I'm a big fan of the Adapter pattern for testing. It is an annoyance that you would have to do such a thing, but the code itself is trivial and the classes can be placed in a project folder to hide them away from your main project.
For example, I have a FileInfoAdapter and DirectoryInfoAdapter that wrap those classes that touch the filesystem.
FileInfoAdapter:
public class FileInfoAdapter : IFileInfo
{
private readonly FileSystemInfo _fi;
public FileInfoAdapter(string fileName)
: this(new FileInfo(fileName))
{ }
public FileInfoAdapter(FileSystemInfo fi)
{
_fi = fi;
}
public string Name { get { return _fi.Name; } }
public string FullName { get { return _fi.FullName; } }
public bool Exists { get { return _fi.Exists; } }
}

Cast into new Object, Copy values by Property Name

I have the following:
Class 1 (Text, State, Level)
Class 2 (Text, State, Level, Ident)
Is there a way for me to cast an object of Class 2 into into Class 1, and not having to do the usual cast code (Text = c.Text, State = c.State etc.)? Possibly by identifying the property names of each class and copying the value over?
Why not derive Class 2 from Class 1, or have a common base class?
e.g.
class Class1
{
string Text;
string State;
int Level;
}
class Class2 : Class1
{
int Ident;
// ...
}
A Class 2 instance can now be used everywhere a Class 1 instance is required.
Here is a very simple example without any error checking, it simply uses reflection to iterate over the properties of the source object and set the value of the destination object only if the types match.
class Program
{
static void Main(string[] args)
{
var bar = new Bar();
var foo = new Foo {A = 10, B = "Hello World"};
foo.CopyTo(bar);
Console.WriteLine("{0} - {1}", bar.A, bar.B);
}
}
public static class Extensions
{
public static void CopyTo(this object source, object destination)
{
var sourceType = source.GetType();
var destinationType = destination.GetType();
const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
var properties = sourceType.GetProperties(flags);
foreach (var sourceProperty in properties)
{
var destinationProperty = destinationType.GetProperty(sourceProperty.Name, flags);
if (destinationProperty.PropertyType.Equals(sourceProperty.PropertyType))
{
destinationProperty.SetValue(destination, sourceProperty.GetValue(source, null), null);
}
}
}
}
Maybe the problem is more complicated than the question. If not, have you tried inheritance?
class Class1
{
//Text, State, Level
}
class Class2 : Class1
{
//Indent
}
Since Class2 inherits from class 1, you can pass it around as Class1 no casting needed. This works for example:
Class1 obj = new Class2();

Categories

Resources