Custom Attributes and Accessing Them In C# - c#

I am working on an application that stores data in the ConfigurationManager.AppSettings file, and I am wanting to implement it in a different way than how I do right now. Currently, I have an interface (see below) that each class with saveable traits needs to implement, then call the static save methods from my Config class (example below). I don't like the coupling between my Config class and the class with the saveable data, so my ideal would be to have an attribute that indicates a property should be saved. Then, instead of calling the SaveData or LoadData functions in my manager class, I would call a function that sets/saves all the attributed properties. This seems similar to how [Serializeable] works in default C#, so I imagine it's possible somehow. However, most of my searches have been fruitless. Any ideas on how to implement something like this?
Interface
Example

Reflection is what you're looking for.
Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them.
Assuming that you're only interested in properties, you can use typeof or GetType to get an instance of System.Type. You can then call GetProperties to get an IEnumerable<PropertyInfo>. PropertyInfo has an Attributes property that you can use to retrieve the attributes for that property. You can also use an instance of PropertyInfo to retrieve the value of the property.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
[AttributeUsage(AttributeTargets.Property)]
public class MyAttribute : Attribute
{
}
public class Foo
{
[My]
public string Bar { get; set; }
public string Baz { get; set; }
[My]
public string Id { get; set; }
}
public static class Utilities
{
public static IEnumerable<PropertyInfo> GetPropertiesWithMyAttribute(object obj)
{
return obj.GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Where(pi => pi.CustomAttributes.Any(ca => ca.AttributeType == typeof(MyAttribute)));
}
}
class Program
{
static void Main(string[] args)
{
var foo = new Foo()
{
Bar = "Bar_Value",
Baz = "Baz_Value",
Id = "Id_Value"
};
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
Console.WriteLine($"{pi.Name}: {pi.GetMethod.Invoke(foo, null).ToString()}");
}
foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
{
pi.SetMethod.Invoke(foo, new object[] { $"{pi.Name}_Value_Reflection" });
}
Console.WriteLine(foo.Bar);
Console.WriteLine(foo.Baz);
Console.WriteLine(foo.Id);
Console.ReadKey();
}
}
Of course, this example only string properties. You're going to have to figure out some way to deal with properties that aren't strings; for example you haven an ObservableCollection in your example.

Related

Dynamic assigned Properties for CsvHelper.Configuration.ClassMap<T>

I want to use CsvHelper.Configuration.ClassMap by dynamically assigned properties.
Usually you map a Property like this in a static manner: You have to assign each property and its 'text to display'.
using CsvHelper.Configuration;
public sealed class CleanSQLRowDescriptorMap : ClassMap<CleanSQLRowDescriptor>
{
public CleanSQLRowDescriptorMap()
{
Map(f => f.OriginalIndex).Name("Original Index");
Map(f => f.OriginalRow).Name("Original Row");
}
}
I want to do the following:
using CsvHelper.Configuration;
public sealed class CleanSQLRowDescriptorMap : ClassMap<CleanSQLRowDescriptor>
{
public CleanSQLRowDescriptorMap()
{
// Filter by attribute (implementation returns PropertyInfo List)
List<PropertyInfo> mappedProperties = CleanSQLRowDescriptor.Create().FilterPropertiesByAttribute();
// Dynamically assign each property and its assigned 'attribute value'
// At the moment I mapped the PropertyInfo.Name, but I actually need to use the Property as the static example above.
// Also need to figure out how to get the Attribute value (DisplayName in this example).
mappedProperties.ForEach(prop => Map(f => prop.Name).Name(prop.Name));
}
}
I currently have the following method used above:
[DisplayName("Original Index")]
public int OriginalIndex { get; set; }
[DisplayName("Original Row")]
public string OriginalRow { get; set; }
public string DonotWantToAssignThis { get; set; }
public List<PropertyInfo> FilterPropertiesByAttribute()
{
// This function already returns only the attributes that use
// [DisplayName] and other attributes defined for other properties,
// ignoring other properties that do not have any of these attributes.
return properties;
}
How can I use the PropertyInfo List of items to dynamically assign the ClassMap? I want to create a base class with these attributes as filters and all the classes implementing this base class would have the same capability, making it easier to 'maintain the mappings'.
I managed to figure it out, VS Code did not give me all the overloads for Map() function, so I missed overloads.
This one is used in all examples:
MemberMap<TClass, TMember> Map<TMember>(Expression<Func<TClass, TMember>> expression, bool useExistingMap = true);
I found this inside JoshClose/CSVHelper:
public MemberMap Map(Type classType, MemberInfo member, bool useExistingMap = true)
So instead of using 'Expression that requires the property name as TMember' which does not take the type I can now assign the MemberInfo directly.
The code below just shows a solution for a single attribute [DisplayName] by using its .DisplayName property value.
For additional Attributes like I have at the moment, I will need to handle the property value differently:
mappedProperties.ForEach(prop =>
{
Map(typeof(CleanSQLRowDescriptor), prop).Name(prop.GetCustomAttribute<DisplayNameAttribute>().DisplayName);
});

Why is it impossible to cast to a derived type [duplicate]

Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.
I have tried it and it creates a run-time error.
No. A reference to a derived class must actually refer to an instance of the derived class (or null). Otherwise how would you expect it to behave?
For example:
object o = new object();
string s = (string) o;
int i = s.Length; // What can this sensibly do?
If you want to be able to convert an instance of the base type to the derived type, I suggest you write a method to create an appropriate derived type instance. Or look at your inheritance tree again and try to redesign so that you don't need to do this in the first place.
No, that's not possible since assigning it to a derived class reference would be like saying "Base class is a fully capable substitute for derived class, it can do everything the derived class can do", which is not true since derived classes in general offer more functionality than their base class (at least, that's the idea behind inheritance).
You could write a constructor in the derived class taking a base class object as parameter, copying the values.
Something like this:
public class Base {
public int Data;
public void DoStuff() {
// Do stuff with data
}
}
public class Derived : Base {
public int OtherData;
public Derived(Base b) {
this.Data = b.Data;
OtherData = 0; // default value
}
public void DoOtherStuff() {
// Do some other stuff
}
}
In that case you would copy the base object and get a fully functional derived class object with default values for derived members. This way you can also avoid the problem pointed out by Jon Skeet:
Base b = new Base();//base class
Derived d = new Derived();//derived class
b.DoStuff(); // OK
d.DoStuff(); // Also OK
b.DoOtherStuff(); // Won't work!
d.DoOtherStuff(); // OK
d = new Derived(b); // Copy construct a Derived with values of b
d.DoOtherStuff(); // Now works!
Solution with JsonConvert (instead of typecast)
Today i faced the same issue and i found a simple and quick solution to the problem using JsonConvert.
var base = new BaseClass();
var json = JsonConvert.SerializeObject(base);
DerivedClass derived = JsonConvert.DeserializeObject<DerivedClass>(json);
I had this problem and solved it by adding a method that takes a type parameter and converts the current object into that type.
public TA As<TA>() where TA : Base
{
var type = typeof (TA);
var instance = Activator.CreateInstance(type);
PropertyInfo[] properties = type.GetProperties();
foreach (var property in properties)
{
property.SetValue(instance, property.GetValue(this, null), null);
}
return (TA)instance;
}
That means that you can use it in you code like this:
var base = new Base();
base.Data = 1;
var derived = base.As<Derived>();
Console.Write(derived.Data); // Would output 1
As many others have answered, No.
I use the following code on those unfortunate occasions when I need to use a base type as a derived type. Yes it is a violation of the Liskov Substitution Principle (LSP) and yes most of the time we favor composition over inheritance. Props to Markus Knappen Johansson whose original answer this is based upon.
This code in the base class:
public T As<T>()
{
var type = typeof(T);
var instance = Activator.CreateInstance(type);
if (type.BaseType != null)
{
var properties = type.BaseType.GetProperties();
foreach (var property in properties)
if (property.CanWrite)
property.SetValue(instance, property.GetValue(this, null), null);
}
return (T) instance;
}
Allows:
derivedObject = baseObect.As<derivedType>()
Since it uses reflection, it is "expensive". Use accordingly.
No it is not possible, hence your runtime error.
But you can assign an instance of a derived class to a variable of base class type.
As everyone here said, that's not possible directly.
The method I prefer and is rather clean, is to use an Object Mapper like AutoMapper.
It will do the task of copying properties from one instance to another (Not necessarily the same type) automatically.
In c# 9.0 you can try to use records for this. They have default copy constructor that copy all fields - no need to use reflection / constructor with all fields.
public record BaseR
{
public string Prop1 { get; set; }
}
public record DerivedR : BaseR
{
public DerivedR(BaseR baseR) : base(baseR) { }
public string Prop2 { get; set; }
}
var baseR = new BaseR { Prop1 = "base prob" };
var derivedR = new DerivedR(baseR) { Prop2 = "new prop" };
Not in the Traditional Sense... Convert to Json, then to your object, and boom, done! Jesse above had the answer posted first, but didn't use these extension methods which make the process so much easier. Create a couple of extension methods:
public static string ConvertToJson<T>(this T obj)
{
return JsonConvert.SerializeObject(obj);
}
public static T ConvertToObject<T>(this string json)
{
if (string.IsNullOrEmpty(json))
{
return Activator.CreateInstance<T>();
}
return JsonConvert.DeserializeObject<T>(json);
}
Put them in your toolbox forever, then you can always do this:
var derivedClass = baseClass.ConvertToJson().ConvertToObject<derivedClass>();
Ah, the power of JSON.
There are a couple of gotchas with this approach: We really are creating a new object, not casting, which may or may not matter. Private fields will not be transferred, constructors with parameters won't be called, etc. It is possible that some child json won't be assigned. Streams are not innately handled by JsonConvert. However, if our class doesn't rely on private fields and constructors, this is a very effective method of moving data from class to class without mapping and calling constructors, which is the main reason why we want to cast in the first place.
Expanding on #ybo's answer - it isn't possible because the instance you have of the base class isn't actually an instance of the derived class. It only knows about the members of the base class, and doesn't know anything about those of the derived class.
The reason that you can cast an instance of the derived class to an instance of the base class is because the derived class actually already is an instance of the base class, since it has those members already. The opposite cannot be said.
You can cast a variable that is typed as the base-class to the type of a derived class; however, by necessity this will do a runtime check, to see if the actual object involved is of the correct type.
Once created, the type of an object cannot be changed (not least, it might not be the same size). You can, however, convert an instance, creating a new instance of the second type - but you need to write the conversion code manually.
You have to use an object cloner/copier that will assign all the properties one by one.
Doing this by hand is inefficient and not future-proof. But serializing & deserializing to JSON and back is not the best solution, it is slow and very memory inefficient.
However, using AutoMapper is fast. PropMapper is even faster.
PS. Disclosure: I am a contributor at PropMapper open source project.
No, it is not possible.
Consider a scenario where an ACBus is a derived class of base class Bus. ACBus has features like TurnOnAC and TurnOffAC which operate on a field named ACState. TurnOnAC sets ACState to on and TurnOffAC sets ACState to off. If you try to use TurnOnAC and TurnOffAC features on Bus, it makes no sense.
class Program
{
static void Main(string[] args)
{
a a1 = new b();
a1.print();
}
}
class a
{
public a()
{
Console.WriteLine("base class object initiated");
}
public void print()
{
Console.WriteLine("base");
}
}
class b:a
{
public b()
{
Console.WriteLine("child class object");
}
public void print1()
{
Console.WriteLine("derived");
}
}
}
when we create a child class object,the base class object is auto initiated so base class reference variable can point to child class object.
but not vice versa because a child class reference variable can not point to base class object because no child class object is created.
and also notice that base class reference variable can only call base class member.
There actually IS a way to do this. Think about how you might use Newtonsoft JSON to deserialize an object from json. It will (or at least can) ignore missing elements and populate all the elements that it does know about.
So here's how I did it. A small code sample will follow my explanation.
Create an instance of your object from the base class and populate it accordingly.
Using the "jsonconvert" class of Newtonsoft json, serialize that object into a json string.
Now create your sub class object by deserializing with the json string created in step 2. This will create an instance of your sub class with all the properties of the base class.
This works like a charm! So.. when is this useful? Some people asked when this would make sense and suggested changing the OP's schema to accommodate the fact that you can't natively do this with class inheritance (in .Net).
In my case, I have a settings class that contains all the "base" settings for a service. Specific services have more options and those come from a different DB table, so those classes inherit the base class. They all have a different set of options. So when retrieving the data for a service, it's much easier to FIRST populate the values using an instance of the base object. One method to do this with a single DB query. Right after that, I create the sub class object using the method outlined above. I then make a second query and populate all the dynamic values on the sub class object.
The final output is a derived class with all the options set. Repeating this for additional new sub classes takes just a few lines of code. It's simple, and it uses a very tried and tested package (Newtonsoft) to make the magic work.
This example code is vb.Net, but you can easily convert to c#.
' First, create the base settings object.
Dim basePMSettngs As gtmaPayMethodSettings = gtmaPayments.getBasePayMethodSetting(payTypeId, account_id)
Dim basePMSettingsJson As String = JsonConvert.SerializeObject(basePMSettngs, Formatting.Indented)
' Create a pmSettings object of this specific type of payment and inherit from the base class object
Dim pmSettings As gtmaPayMethodAimACHSettings = JsonConvert.DeserializeObject(Of gtmaPayMethodAimACHSettings)(basePMSettingsJson)
You can use an Extention:
public static void CopyOnlyEqualProperties<T>(this T objDest, object objSource) where T : class
{
foreach (PropertyInfo propInfo in typeof(T).GetProperties())
if (objSource.GetType().GetProperties().Any(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()))
propInfo.SetValue(objDest, objSource.GetType().GetProperties().First(z => z.Name == propInfo.Name && z.GetType() == propInfo.GetType()).GetValue(objSource));
}
In Code:
public class BaseClass
{
public string test{ get; set;}
}
public Derived : BaseClass
{
//Some properies
}
public void CopyProps()
{
BaseClass baseCl =new BaseClass();
baseCl.test="Hello";
Derived drv=new Derived();
drv.CopyOnlyEqualProperties(baseCl);
//Should return Hello to the console now in derived class.
Console.WriteLine(drv.test);
}
Might not be relevent, but I was able to run code on a derived object given its base. It's definitely more hacky than I'd like, but it works:
public static T Cast<T>(object obj)
{
return (T)obj;
}
...
//Invoke parent object's json function
MethodInfo castMethod = this.GetType().GetMethod("Cast").MakeGenericMethod(baseObj.GetType());
object castedObject = castMethod.Invoke(null, new object[] { baseObj });
MethodInfo jsonMethod = baseObj.GetType ().GetMethod ("ToJSON");
return (string)jsonMethod.Invoke (castedObject,null);
You can do this using generic.
public class BaseClass
{
public int A { get; set; }
public int B { get; set; }
private T ConvertTo<T>() where T : BaseClass, new()
{
return new T
{
A = A,
B = B
}
}
public DerivedClass1 ConvertToDerivedClass1()
{
return ConvertTo<DerivedClass1>();
}
public DerivedClass2 ConvertToDerivedClass2()
{
return ConvertTo<DerivedClass2>();
}
}
public class DerivedClass1 : BaseClass
{
public int C { get; set; }
}
public class DerivedClass2 : BaseClass
{
public int D { get; set; }
}
You get three benefits using this approach.
You are not duplicating the code
You are not using reflection (which is slow)
All of your conversions are in one place
I know this is old but I've used this successfully for quite a while.
private void PopulateDerivedFromBase<TB,TD>(TB baseclass,TD derivedclass)
{
//get our baseclass properties
var bprops = baseclass.GetType().GetProperties();
foreach (var bprop in bprops)
{
//get the corresponding property in the derived class
var dprop = derivedclass.GetType().GetProperty(bprop.Name);
//if the derived property exists and it's writable, set the value
if (dprop != null && dprop.CanWrite)
dprop.SetValue(derivedclass,bprop.GetValue(baseclass, null),null);
}
}
I combined some portions of the previous answers (thanks to those authors) and put together a simple static class with two methods that we're using.
Yes, it's simple, no it doesn't cover all scenarios, yes it could be expanded and made better, no it's not perfect, yes it could possibly be made more efficient, no it's not the greatest thing since sliced bread, yes there are full-on robust nuget package object mappers out there that are way better for heavy use, etc etc, yada yada - but it works for our basic needs though :)
And of course it will try to map values from any object to any object, derived or not (only the public properties that are named the same of course - ignores the rest).
USAGE:
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
// creates new object of type "RealPerson" and assigns any matching property
// values from the puppet object
// (this method requires that "RealPerson" have a parameterless constructor )
RealPerson person = ObjectMapper.MapToNewObject<RealPerson>(puppet);
// OR
// create the person object on our own
// (so RealPerson can have any constructor type that it wants)
SesameStreetCharacter puppet = new SesameStreetCharacter() { Name = "Elmo", Age = 5 };
RealPerson person = new RealPerson("tall") {Name = "Steve"};
// maps and overwrites any matching property values from
// the puppet object to the person object so now our person's age will get set to 5 and
// the name "Steve" will get overwritten with "Elmo" in this example
ObjectMapper.MapToExistingObject(puppet, person);
STATIC UTILITY CLASS:
public static class ObjectMapper
{
// the target object is created on the fly and the target type
// must have a parameterless constructor (either compiler-generated or explicit)
public static Ttarget MapToNewObject<Ttarget>(object sourceobject) where Ttarget : new()
{
// create an instance of the target class
Ttarget targetobject = (Ttarget)Activator.CreateInstance(typeof(Ttarget));
// map the source properties to the target object
MapToExistingObject(sourceobject, targetobject);
return targetobject;
}
// the target object is created beforehand and passed in
public static void MapToExistingObject(object sourceobject, object targetobject)
{
// get the list of properties available in source class
var sourceproperties = sourceobject.GetType().GetProperties().ToList();
// loop through source object properties
sourceproperties.ForEach(sourceproperty => {
var targetProp = targetobject.GetType().GetProperty(sourceproperty.Name);
// check whether that property is present in target class and is writeable
if (targetProp != null && targetProp.CanWrite)
{
// if present get the value and map it
var value = sourceobject.GetType().GetProperty(sourceproperty.Name).GetValue(sourceobject, null);
targetobject.GetType().GetProperty(sourceproperty.Name).SetValue(targetobject, value, null);
}
});
}
}
You can use a copy constructor that immediately invokes the instance constructor, or if your instance constructor does more than assignments have the copy constructor assign the incoming values to the instance.
class Person
{
// Copy constructor
public Person(Person previousPerson)
{
Name = previousPerson.Name;
Age = previousPerson.Age;
}
// Copy constructor calls the instance constructor.
public Person(Person previousPerson)
: this(previousPerson.Name, previousPerson.Age)
{
}
// Instance constructor.
public Person(string name, int age)
{
Name = name;
Age = age;
}
public int Age { get; set; }
public string Name { get; set; }
}
Referenced the Microsoft C# Documentation under Constructor for this example having had this issue in the past.
With regarding #MarkusKnappenJohansson answer and below comments we can change his code extending extension function :) so it may update an existing deriving class instance via this code :
public static TDerived As<TDerived>(this Base baseInstance, TDerived updateDerivedInstance = null) where TDerived : Base, new()
{
Type baseType = typeof(Base);
Type derivedType = typeof(TDerived);
PropertyInfo[] properties = baseType.GetProperties();
object instanceDerived = null;
if (updateDerivedInstance == null)
{
instanceDerived = Activator.CreateInstance(derivedType);
}
else
{
instanceDerived = (object)(updateDerivedInstance);
}
foreach (PropertyInfo property in properties)
{
if (property.CanWrite)
{
property.SetValue(instanceDerived, property.GetValue(baseInstance, null), null);
}
}
return (TDerived)instanceDerived;
}
Usage for getting new derived Instance is var base = new Base(); base.Data = 1; var derived = base.As<Derived>(); Console.Write(derived.Data); // Would output 1
Usage for updating existing derived Instance is var derived = new Derived(); var base = new Base(); base.Data = 1; var derivedUpdated = base.As<Derived>(derived); Console.Write(derivedUpdated.Data); // Would output 1
Another solution is to add extension method like so:
public static void CopyProperties(this object destinationObject, object sourceObject, bool overwriteAll = true)
{
try
{
if (sourceObject != null)
{
PropertyInfo[] sourceProps = sourceObject.GetType().GetProperties();
List<string> sourcePropNames = sourceProps.Select(p => p.Name).ToList();
foreach (PropertyInfo pi in destinationObject.GetType().GetProperties())
{
if (sourcePropNames.Contains(pi.Name))
{
PropertyInfo sourceProp = sourceProps.First(srcProp => srcProp.Name == pi.Name);
if (sourceProp.PropertyType == pi.PropertyType)
if (overwriteAll || pi.GetValue(destinationObject, null) == null)
{
pi.SetValue(destinationObject, sourceProp.GetValue(sourceObject, null), null);
}
}
}
}
}
catch (ApplicationException ex)
{
throw;
}
}
then have a constructor in each derived class that accepts base class:
public class DerivedClass: BaseClass
{
public DerivedClass(BaseClass baseModel)
{
this.CopyProperties(baseModel);
}
}
It will also optionally overwrite destination properties if already set (not null) or not.
Is it possible to assign a base class object to a derived class reference with an explicit typecast in C#?.
Not only explicit, but also implicit conversions are possible.
C# language doesn't permit such conversion operators, but you can still write them using pure C# and they work. Note that the class which defines the implicit conversion operator (Derived) and the class which uses the operator (Program) must be defined in separate assemblies (e.g. the Derived class is in a library.dll which is referenced by program.exe containing the Program class).
//In library.dll:
public class Base { }
public class Derived {
[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Implicit(Base a) {
return new Derived(a); //Write some Base -> Derived conversion code here
}
[System.Runtime.CompilerServices.SpecialName]
public static Derived op_Explicit(Base a) {
return new Derived(a); //Write some Base -> Derived conversion code here
}
}
//In program.exe:
class Program {
static void Main(string[] args) {
Derived z = new Base(); //Visual Studio can show squiggles here, but it compiles just fine.
}
}
When you reference the library using the Project Reference in Visual Studio, VS shows squiggles when you use the implicit conversion, but it compiles just fine. If you just reference the library.dll, there are no squiggles.
How about:
public static T As<T>(this object obj)
{
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(obj));
}
Best way to add all base properties to derived item is use reflection in costructor. Try this code, without creating methods or instances.
public Derived(Base item) :base()
{
Type type = item.GetType();
System.Reflection.PropertyInfo[] properties = type.GetProperties();
foreach (var property in properties)
{
try
{
property.SetValue(this, property.GetValue(item, null), null);
}
catch (Exception) { }
}
}
I disagree that it is not possible. You can do it like this:
public class Auto
{
public string Make {get; set;}
public string Model {get; set;}
}
public class Sedan : Auto
{
public int NumberOfDoors {get; set;}
}
public static T ConvertAuto<T>(Sedan sedan) where T : class
{
object auto = sedan;
return (T)loc;
}
Usage:
var sedan = new Sedan();
sedan.NumberOfDoors = 4;
var auto = ConvertAuto<Auto>(sedan);
This is how I solved this for fields. You can do the same iteration through properties if you want. You may want to do some checks for null etc. but this is the idea.
public static DerivedClass ConvertFromBaseToDerived<BaseClass, DerivedClass>(BaseClass baseClass)
where BaseClass : class, new()
where DerivedClass : class, BaseClass, new()
{
DerivedClass derived = (DerivedClass)Activator.CreateInstance(typeof(DerivedClass));
derived.GetType().GetFields().ToList().ForEach(field =>
{
var base_ = baseClass.GetType().GetField(field.Name).GetValue(baseClass);
field.SetValue(derived, base_);
});
return derived;
}
You can just serialize the base object to JSON and then deserialize it to the derived object.
No, see this question which I asked - Upcasting in .NET using generics
The best way is to make a default constructor on the class, construct and then call an Initialise method

Protobuf with many unknown types

What is the best approach when I do not know at runtime which types are de/serialized with protobuf?
Currently I am playing with the idea to extend the RuntimeTypeModel in the type initializers of the types which are candidates for serialization which seems to work pretty well for serialiation. But when deserializing in a different process I would need to load the same type model from somewhere which was used to serialize the types. Is it possible to serialize the RuntimeTypeModel to disk to reuse it later when the serialized data is read again from disk? Ideally I would put the model into the serialized stream as well to have a full self describing object model. Or would I need to record the steps and put this data in front of my serialized stream?
One could create a header which contains the offset to the real data and the runtime type model and the length which would be pretty nice. Or is there a better approach how to deal with a plug in architecture where at serialization time I have all types registered but during deseralization I might stil need to load some types from their respective assemblies because the code was not yet touched?
using ProtoBuf;
using ProtoBuf.Meta;
using System.Collections.Generic;
using System.IO;
namespace protobuf
{
[ProtoContract]
public interface IAbstraction
{
[ProtoMember(1)]
string Name { get; set; }
}
[ProtoContract]
public class Base : IAbstraction
{
static Base()
{
ProtobufTypeModels.MainModel.Add(typeof(IAbstraction), true).AddSubType(101, typeof(Base));
}
[ProtoMember(1)]
public string Name { get; set; }
[ProtoMember(2, AsReference =true)]
public List<IAbstraction> Instances = new List<IAbstraction>();
}
[ProtoContract]
public class Next : Base
{
static Next()
{
ProtobufTypeModels.MainModel.Add(typeof(IAbstraction), true).AddSubType(100, typeof(Next));
}
[ProtoMember(1)]
public string NextName { get; set; }
}
public static class ProtobufTypeModels
{
public static readonly RuntimeTypeModel MainModel = TypeModel.Create();
}
class Program
{
static void Main(string[] args)
{
Base b = new Base { Name = "Alois" };
b.Instances.Add(new Next { Name = "Base", NextName = "Christian" });
b.Instances.Add(new Base { Name = "SecondBase", Instances = b.Instances });
var mem = new MemoryStream();
ProtobufTypeModels.MainModel.Serialize(mem, b);
mem.Position = 0;
var deser = (Base) ProtobufTypeModels.MainModel.Deserialize(mem, null, typeof(Base));
}
}
}
Random thought: you could use .Compile(serializerName,dllPath) after you've finished the initialization and write the baked serializer to disk; then you can reference it, use new SerializerName() to create the instance, and use the .Serialize etc methods from there. The dll will never change. This also means it never has to process any metadata ever again; no reflection, no IL emit, etc.
Other than that: we could possibly do something more gentle in terms of storing the configuration, but: protobuf-net doesn't currently add anything directly to support it, and it would probably be more relevant for you to have your own bespoke configuration data that you simply consume at startup.

Reflection using generics and late-binding. How to cast at run-time?

I am trying to use Generics with Reflection in c# to build a method that can handle multiple classes. I use a 3rd-party DLL that has a bunch of classes and on those classes, there is a method I call. They all return different return types, but I do the same processing once I get the object back (in my example below, that would be AreaA and AreaB).
Basically, I want to develop a method that takes in the class name and the expected return type as Generic variables and then calls the correct method (methodName) which is supplied as a parameter to this method.
The program below compiles fine and runs without error, but the issue is the expected type of the 'area' variable. In the below statements, the first line is type casted to (TArea), and if I hover over it In Visual Studio, the intellisense shows the property 'name', but typing area.name doesn't give me the value. I have to type ((AreaA)area).name.
Problem is the type 'AreaA' could be another type at run-time. In this example, 'AreaB' so I can hard-code a cast.
How can I accomplish casting the 'area' variable to the appropriate type allowing me to see the public methods/properties of the 3rd-parties class?
NOTE: In my example, eveything is in the same class, but in reality the definitions for ServiceA, ServiceB, AreaA and AreaB will be in a 3rd party DLL.
As always, thanks in advance!
Fig 1 - 'area' variable can only get 'name' property if casted to 'AreaA'
area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
AreaA areaa = (AreaA)dfpMethod.Invoke(instance, new object[] { "Area123" });
Fig 2. - Complete Program
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.IO;
namespace ReflectionExample
{
class Sample
{
class ServiceA
{
public int size {get; set;}
public string name {get; set;}
public ServiceA()
{
name = "TestA";
size = 100;
}
public AreaA doWork(string name)
{
return new AreaA(name);
}
}
class AreaA
{
public string name { get; set;}
public AreaA(string name)
{
this.name = name;
}
public AreaA()
{
}
}
class ServiceB
{
public int size { get; set; }
public string name { get; set; }
public ServiceB()
{
name = "TestB";
size = 50;
}
public AreaB doWork(string name)
{
return new AreaB(name);
}
}
class AreaB
{
public string name { get; set; }
public AreaB(string name)
{
this.name = name;
}
public AreaB()
{
}
}
static void Main(string[] args)
{
runService<ServiceA, AreaA>("doWork");
}
private static void runService<TService, TArea>(string methodName)
where TService : class, new()
where TArea : class, new()
{
//Compile time processing
Type areaType = typeof(TArea);
Type serviceType = typeof(TService);
//Print the full assembly name and qualified assembly name
Console.WriteLine("AreaType--Full assembly name:\t {0}.", areaType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("AreaType--Qualified assembly name:\t {0}.", areaType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
Console.WriteLine("ServiceType--Full assembly name:\t {0}.", serviceType.Assembly.FullName.ToString()); // Print the full assembly name.
Console.WriteLine("ServiceType--Qualified assembly name:\t {0}.", serviceType.AssemblyQualifiedName.ToString()); // Print the qualified assembly name.
//This is done because in my code, the assembly doesn't reside in the executiy assembly, it is only setup as a reference
var assembly = Assembly.Load(serviceType.Assembly.FullName);
//Initialize the generic area
TArea area = default(TArea);
//Get an instance of the service so I can invoke the method later on
var instance = Activator.CreateInstance(serviceType);
//Get the methodInfo for the methodName supplied to the runService method
MethodInfo dfpMethod = serviceType.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance);
//area is type casted to (TArea), the intellisense shows the property 'name', but typing area.name doesn't give me the value
//I have to type ((AreaA)area).name. Problem is the type 'AreaA' could be another type. In this example, 'AreaB'
area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
AreaA areaa = (AreaA)dfpMethod.Invoke(instance, new object[] { "Area123" });
Console.WriteLine();
}
}
}
The source of your error is that you're casting all of your return values to type TArea with the statement:
TArea area = (TArea)dfpMethod.Invoke(instance, new object[] { "Area123" });
Per your generic specification, the only thing promised to you by the type TArea is that its a class. Therefore, TArea doesn't give you access to anything but members of the 'object' type.
Instead, do away with the TArea generic argument in favor of using the 'dynamic' keyword:
var area = (dynamic)dfpMethod.Invoke(instance, new object[] { "Area123" });
return area.name; // no error
Note, this is only relevant if the actual types AreaA and AreaB are defined in third party libraries (as you say) and you can't modify them. If you can't modify the classes, you can't introduce an interface (which is what you really need here). If you can't introduce an interface, but all the types expose identical signatures, you can assume the existence of the relevant members using the dynamic type.
If you need to do a lot of work with AreaA/AreaB and you don't want the performance overhead of all the dynamic operations, define your own generalized class that exposes all the signatures you need:
public class MyGenericArea
{
public MyGenericArea(string name)
{
this.Name = name;
}
public string Name {get; set;}
}
Then populate the class using the dynamic casting and return that class type instead:
var area = (dynamic)dfpMethod.Invoke(instance, new object[] { "Area123" });
return new MyGenericArea(area.name);
I think the problem you will have here is mixing dynamically loaded types (Assembly.Load()) with types that are referenced directly from your project and you can see in intellisense, i.e. AreaA.
If you are dynamically loading entire assemblies using reflection, intellisense will do nothing to help you view the class members, as that information needs to be known at compile time, and by definition you are loading assemblies at runtime.
If you just want to view a list of all of the public properties available to your type, then you can use this:
var areaProperties = area.GetType().GetProperties();
But again, this is all done at run time so it wont help you when writing code.
You can dynamically read the value of the "name" property using:
var nameValue = area.GetType().GetProperty("name").GetValue(area);
Essentially, if you want intellisense, reference the dll's directly from your Visual Studio project rather than using Assembly.Load().
Hope that helps.

How to share a static method amongst several class

I'd like to start with something like this:
class A { ... }
class B { ... }
class C { ... }
Where A, B and C have a static method MyName.
Then I could do:
Console.WriteLine(A.MyName());
Console.WriteLine(B.MyName());
Console.WriteLine(C.MyName());
Then after I should be able to do something like this.
foreach(var type in new[] { typeof(A), typeof(B), typeof(C)) {
??? Console.WriteLine(t.MyName());
}
How could I do that?
I'd also like to be able to do the following (but that may be impossible):
??? x = new A();
Console.WriteLine(x.MyName());
x = new B();
Console.WriteLine(x.MyName());
What you're trying to do here is associate Metadata with a type, which can be queried if you know the type. The standard practice for doing this is to use Custom Attributes. You can query these attributes in a type-safe way and extract the associated information for each attribute. They are quite flexible in how you specify their inheritance and whether you can apply more than one of the same attribute type. They can also be applied to other things besides classes, like properties or fields, which can be handy.
Here's a simple demo program (the null check isn't strictly necessary here, but just demonstrating how you check whether an attribute actually exists.) Note that the extension method that provides a generic GetCustomAttribute was only added in .NET 4.5. Prior versions will require you to use a non-generic version and cast it to the appropriate attribute type.
class Program
{
static void Main(string[] args)
{
var types = new[] {typeof(A), typeof(B), typeof(C)};
foreach (var type in types)
{
var attribute = type.GetCustomAttribute<NameAttribute>();
if (attribute != null)
Console.WriteLine(attribute.Name);
}
Console.ReadLine();
}
public sealed class NameAttribute : Attribute
{
public string Name { get; private set; }
public NameAttribute(string name)
{
Name = name;
}
}
[Name("A Name")]
public class A
{
}
[Name("B Name")]
public class B
{
}
[Name("C Name")]
public class C
{
}
}
In order to share some static member between classes you need to inherit from base class which will contain static member:
public class Base
{
public static string MyName() { return "Bob"; }
}
public class A : Base
{
}
public class B : Base
{
}
You can't do what you are trying in your foreach loop, because variable t has type Type and Type do not have any MyName properties. You should use reflection to get MyName value:
Console.WriteLine(A.MyName()); // Bob
Console.WriteLine(B.MyName()); // Bob
foreach(var type in new[] { typeof(A), typeof(B) })
{
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;
var method = type.GetMethod("MyName", flags);
Console.WriteLine(method.Invoke(null, null));
}
This code prints Bob for both types.

Categories