protobuf-net inheritance - c#

Marc mentioned on stackoverflow that it will be possible in v2 of protobuf-net to use ProtoInclude attribute (or similar approach) to serialize/deserialize class hierarchy without a need to specify each subtype in the base class. Is this implemented yet? We have a plugin interface that can be derived in external libraries, so there is no way of knowing what the derived types will be. We could maintain unique numbering between types though, but I couldn’t find any examples on the net, short of using ProtoInclude attribute which requires a subtype to be specified.
How would I go about implementing inheritance with protobuf-net like that if I don't know what the subtypes are?

If you can't specify the subtypes in attributes (because it isn't known at compile-time) you have 2 options (both of which only apply to "v2", available as beta):
use a RuntimeTypeModel, rather than the static Serializer methods (which are now just a short-cut to RuntimeTypeModel.Default); tell the model about the inheritance (example below)
add DynamicType = true to the [ProtoMember(...)] in question
The second is not very pure protobuf - it embeds type information, which I don't really love but people just kept asking for. The first is my preferred option. To add subtypes at runtime:
var model = TypeModel.Create();
var type = model.Add(typeof(YourBaseType), true);
var subTypeA = model.Add(typeof(SomeSubType), true);
var subTypeB = model.Add(typeof(SomeOtherSubType), true);
type.AddSubType(4, typeof(SomeSubType));
type.AddSubType(5, typeof(SomeOtherSubType));
the true in the above means "use normal rules to add member properties automatically" - you can also take control of that and specify the properties (etc) manually if you prefer.
Note that a TypeModel should be cached and re-used (not created per object you need to serialize), as it includes some "emit" code to generate methods. Re-using it will be faster and require less memory. The type-model is thread-safe, and can be used to serialize/deserialize multiple streams concurrently on different threads.

To further expand Marc's answer, specifically dealing with RuntimeTypeModel, this is one way to write it:
RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(20, typeof(DerivedClass));
If you have more classes derived from derived classes, link them like this
RuntimeTypeModel.Default[typeof(DerivedClass)].AddSubType(20, typeof(DerivedFromDerivedClass ));
And so on.
You can then use Serializer.Serialize(file,object), as you would normally with protobuf-net.
This works across projects and namespaces.

By adding helper extension method:
public static class RuntimeTypeModelExt
{
public static MetaType Add<T>(this RuntimeTypeModel model)
{
var publicFields = typeof(T).GetFields().Select(x => x.Name).ToArray();
return model.Add(typeof(T), false).Add(publicFields);
}
}
You can streamline sub-type registration like this:
private static RuntimeTypeModel CreateModel()
{
var model = TypeModel.Create();
model.Add<ExportInfo>();
model.Add<RegistrationInfo>();
model.Add<FactorySetupInfo>()
.AddSubType(101, model.Add<ServiceSetupInfo>().Type)
.AddSubType(102, model.Add<GenericWrapperSetupInfo>().Type)
.AddSubType(103, model.Add<DecoratorSetupInfo>().Type);
return model;
}

I solved this by completely flattening the hierarchy of fields for each ProtoContract. I also assume all fields will be serialized unless [ProtoIgnore] exists and therefore do not decorate fields with [ProtoMember(n)]. It does not need oneOf or [ProtoInclude]. This is what I use, no more scratching my head wondering what went wrong in the numbering etc. Feel free to expand on it to your needs.
A note: it takes any Type decorated with ProtoContract in an Assembly, flattens it's fields, ignores those with [ProtoIgnore], then automatically builds up all the ProtoMembers(n) (so no need for manual numbering).
It also accepts a single Generic Argument Protocol, where you supply the known Generic types e.g MyContract'1 and you supply typeof(MyContract2) such that the concreted type for serializing is MyContract<MyContract2>
Edit: This is a basic example and serves my needs. You may wish to extend it and sort the fields like so, so that you can manage adding new fields and retain backwards compat.
https://learn.microsoft.com/en-us/dotnet/framework/wcf/feature-details/data-member-order
To this end you could ignore Proto attributes entirely in the code and replace with DataContract, DataMember etc for discovery and let your contracts be both DataContracts and ProtoContracts with known ordering for both.
/// <summary>
/// <see cref="CompileProtocols(Assembly, Type[])"/>.
/// </summary>
/// <param name="knownGenericArguments"></param>
/// <returns></returns>
public static IEnumerable<Type> CompileProtocols(params Type[] knownGenericArguments)
{
var rv = CompileProtocols(Assembly.GetExecutingAssembly(), knownGenericArguments);
return rv;
}
/// <summary>
/// Compiles protocols that are non generic or take a single generic argument (`1). Single generic argument protocols
/// will be concreted against the knownGenericArguments passed into the method.
/// </summary>
/// <param name="genericArgumentTypes"></param>
public static IEnumerable<Type> CompileProtocols(Assembly inAssembly, params Type[] knownGenericArguments)
{
var runtimeProtocolTypes = new List<Type>();
var assemblyProtocolTypes =inAssembly.GetTypes().Where(t => t.GetCustomAttribute<ProtoContractAttribute>() != null);
foreach(var assemblyProtocolType in assemblyProtocolTypes)
{
if(assemblyProtocolType.IsGenericType == false)
{
runtimeProtocolTypes.Add(assemblyProtocolType);
}
else
{
if (knownGenericArguments.Length > 0)
{
var assemblyTypeGenericArgs = assemblyProtocolType.GetGenericArguments();
if (assemblyTypeGenericArgs.Length == 1)
{
foreach (var knownGenericArgument in knownGenericArguments)
{
var runtimeGenericType = assemblyProtocolType.MakeGenericType(knownGenericArgument);
runtimeProtocolTypes.Add(runtimeGenericType);
}
}
}
}
}
BuildModel(runtimeProtocolTypes);
return runtimeProtocolTypes;
}
/// <summary>
/// Builds and optionally compiles (default=true) the RuntimeTypeModel. In this case it uses the RumtimeTypeModel.Default
/// with a CompileInPlace.
///
/// Note: You might wish to change this to build another model or return a complete Compiled model instead.
/// </summary>
/// <param name="protocolTypes"></param>
/// <param name="compile"></param>
private static void BuildModel(IEnumerable<Type> protocolTypes, bool compile = true)
{
foreach (var protocolType in protocolTypes)
{
int index = 1;
var fields = protocolType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy).Where(f => f.GetCustomAttribute<ProtoIgnoreAttribute>() == null);
var metaType = RuntimeTypeModel.Default.Add(protocolType);
foreach (var field in fields)
{
metaType.AddField(index, field.Name);
index++;
}
}
if (compile)
{
RuntimeTypeModel.Default.CompileInPlace();
}
}

Related

Static generic delegate field in C#

Using generic types is nice and easy, but since I tried to implement my own generic types, I came to a problem which I couldn't solve by myself yet. I want to have a static field for a delegate. This is how it works for me when using non-generic types:
delegate Type Type_Delegate(Type type);
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
// Now the TypeMethod can be called like this from somewhere in the Code:
ClassName.TypeMethod(typeof(string));
But when using any generic type:
delegate T Type_Delegate<T>(T type);
// This static field syntax isn't allowed:
static Type_Delegate<T> TypeMethod = new Type_Delegate<T>(TypeMethodName);
// It would be a dream to be able to use it like this now:
ClassName.TypeMethod<string>("Hello world!");
T is unknown type/namespace.
When I experiment with the syntax:
// This static field syntax isn't allowed, too:
static Type_Delegate TypeMethod = new Type_Delegate(TypeMethodName);
Type arguments are missing for usage.
I tried several ideas about the possible syntax, but not succeed...
How do I need to change the static field syntax to work as assumed, so the code is able to set a generic delegate method as value, without having to specify a type at that time?
Edit: I also tried to wrap the delegate and field with a generic static class, but there I still have the same syntax issues, when I want to set the field value without specifying the type.
Edit 2: Maybe the following example workaround apporach will clarify my thoughts more, since I think most commenters didn't understand my goal (maybe it's my bad English, too):
using System;
using System.Linq;
using System.Reflection;
namespace Testing
{
public static class GenericTest
{
public interface IGenericClass<T>
{
T Method(T parameter);
}
public class GenericClass<T> : IGenericClass<T>
{
public T Method(T parameter)
{
// Just a stupid example, don't think about that...
return parameter;
}
}
/// <summary>
/// The value must be any type that implements the IGenericClass<T> interface
/// </summary>
public static Type GenericField = typeof(GenericClass<>);
/// <summary>
/// Call the method of an instance of the type that was set to GenericField
/// </summary>
/// <param name="T">The type to use for creating an instance of the generic class</param>
/// <param name="parameter">The parameter for calling the method of the generic class</param>
/// <returns>Any value of type "T"</returns>
public static dynamic GenericMethod(Type T, object parameter)
{
var genericType = GenericField.MakeGenericType(new Type[] { T });
MethodInfo method = genericType.GetMethod("Method");
if (method == null) throw new InvalidCastException("GenericField isn't a IGenericClass<T> type");
return method.Invoke(Activator.CreateInstance(genericType), new object[] { parameter });
}
}
}
Now I can do something like this somewhere else in the code:
MessageBox.Show(Testing.GenericTest.GenericMethod(typeof(string), "Hello world!"));
In this example solution I need to work with classes and an interface, require reflections, it's a whole bunch of code required to get the same functionality for a generic (class-)method, as I can get with only two lines of code when working with non-generic methods (using delegates). What an overhead, what a hack - I try to avoid doing such nasty things in productive code. But if there are no better 2 lines of Code that do the same, this time I will have to fight my ego...
It is possible, by wrapping it in a generic class definition and using the class type parameter.
static class C<T>
{
public static DelegateTypePrototype<T> DelegateType;
}
This way the type only has to be resolved once you "request" an instance of the class. At least that's my intuitive understanding coming from C++ templates background.

Get base class hierarchy methods with IMetaDataImport EnumMethods

I'm trying to implement managed debugger looking at MDBG sample.
MDBG is capable of resolving function names within given scope, but it's not taking in consideration base classes.
MDBG is doing this:
/// <summary>
/// Resolves a Function from a Module, Class Name, and Function Name.
/// </summary>
/// <param name="mdbgModule">The Module that has the Function.</param>
/// <param name="className">The name of the Class that has the Function.</param>
/// <param name="functionName">The name of the Function.</param>
/// <returns>The MDbgFunction that matches the given parameters.</returns>
public MDbgFunction ResolveFunctionName(MDbgModule mdbgModule, string className, string functionName) {
...
foreach (MethodInfo mi in t.GetMethods()) {
if (mi.Name.Equals(functionName)) {
func = mdbgModule.GetFunction((mi as MetadataMethodInfo).MetadataToken);
break;
}
}
return func;
}
While the Type.GetMethods() is overriden and has this implementation, using IMetaDataImport.EnumMethods:
public override MethodInfo[] GetMethods(BindingFlags bindingAttr) {
ArrayList al = new ArrayList();
IntPtr hEnum = new IntPtr();
int methodToken;
try {
while (true) {
int size;
m_importer.EnumMethods(ref hEnum, (int) m_typeToken, out methodToken, 1, out size);
if (size == 0) {
break;
}
al.Add(new MetadataMethodInfo(m_importer, methodToken));
}
}
finally {
m_importer.CloseEnum(hEnum);
}
return (MethodInfo[]) al.ToArray(typeof (MethodInfo));
}
The problem is that m_importer.EnumMethods() Enumerates MethodDef tokens representing methods of the specified type, but I'm interested in all methods from the class hierarchy.
How can I get all the Methods defined in class hierarchy? (Obviously, common methods like reflection cannot be used, since I'm analyzing type defined in other process)
My limited knowledge of interop and deep CLR/CIL structure creates impediments for finding the right way to go here.
Any advice/suggestion is welcome!
Regards,
GetTypeProps will return the metadata token of the base type in ptkExtends, you can use that to walk up the inheritance tree and collect the methods from each as you go.
Be aware, however, that the metadata token might not be a TypeDef. It could be a TypeRef (requiring you to resolve the type) or a TypeSpec (requiring you to parse the type signature and extract an appropriate TypeDef/TypeRef).

How to return a collection based on the inputs (generic)

beginner:
want to write a method to return a generic collection as:
public IEnumerable<T> ABC( string x){
if( x== "1")
{ Collection<A> needs to be returned}
if(x=="2")
{ Collection<B> needs to be returned}
..
so on
}
Questions:
- based on "X" passed to the method different types of collections are initialized and need to be returned? how can i do that?
- is this the correct approach?
- any links to get more details on generic usages?
AFAIK, the type parameter (here T) must be known at compile time. Which means it can't change while running. What you could do is make it IEnumerable<Object>. Since every other type has Object as a base type, I'm pretty sure you could return an IEnumerable of anything at that point. Though you may need to cast in/out of Object on the way.
no need to pass string to identify the type of class .just call with the following generic method ,it will intialize the List of that T type.
/// <summary>
/// Gets the initialize generic list.
/// </summary>
/// <typeparam name="T"></typeparam>
public IList<T> GetInitializeGenericList<T>() where T : class
{
Type t = typeof(List<>);
Type typeArgs =typeof(T);
Type type = t.MakeGenericType(typeArgs);
// Create the List according to Type T
dynamic reportBlockEntityCollection = Activator.CreateInstance(type);
// If you want to pull the data into initialized list you can fill the data
//dynamic entityObject = Activator.CreateInstance(typeArgs);
//reportBlockEntityCollection.Add(entityObject);
return reportBlockEntityCollection;
}

Extension Methods and generics - How should I be doing this?

I'm in the middle of overhauling some code and I hit a bit of a snag.
This is the method which I currently have, it needs reworking to support some structure changes:
/// <summary>
/// Recreates a dashboard control based off of its settings.
/// </summary>
/// <typeparam name="T"> The type of control to be recreated. </typeparam>
/// <param name="settings"> The known settings needed to recreate the control.</param>
/// <returns> The recreated control. </returns>
public static T Recreate<T>(ISetting<T> settings) where T : new()
{
T _control = new T();
settings.SetSettings(_control);
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
ISetting is being removed completely in favor of an extension method known to _control.
So, I have now:
public static class RadControlExtensions
{
public static RadDockZoneSetting GetSettings(this RadDockZone dockZone)
{
RadDockZoneSetting radDockZoneSetting = new RadDockZoneSetting(dockZone.UniqueName, dockZone.ID, dockZone.Skin, dockZone.MinHeight,
dockZone.HighlightedCssClass, dockZone.BorderWidth, dockZone.Parent.ID);
return radDockZoneSetting;
}
public static RadTabSetting GetSettings(this RadTab tab, int index)
{
RadTabSetting radTabSetting = new RadTabSetting(tab.Text, tab.Value, index);
return radTabSetting;
}
//Continued
}
The control that is being recreated is guaranteed to have this extension method (would be nice to enforce this, though.)
I'm now at:
public static T Recreate<T>() where T : new()
{
T _control = new T();
//Not right -- you can't cast a control to an extension method, obviously, but
//this captures the essence of what I would like to accomplish.
(_control as RadControlExtension).SetSettings();
Logger.DebugFormat("Recreated control {0}", (_control as Control).ID);
return _control;
}
What should I be looking into to support this, if possible?
If you know that every _control that gets passed will be a RadDockZone (or derived from RadDockZone) just do this:
T _control = new T();
(RadDockZone)_control.SetSettings();
Logger.DebugFormat("Recreated control ... //rest of code here
If it's not always going to be a RadDockZone, you'll need to do some type checking to get the right type to call the extension method. I'm presuming, there, that you have a .SetSettings() extension method on all the possible Types that could be passed to your Recreate method.
You need to cast your T to something that is supported by your extension method.
(_control as RadDockZone).GetSettings
Extension methods operate on a type they are not a type in the traditional sense. The 'SomeFn(string this)' makes your extension work on things that are strings which would be strings and anything derived from them.
If I understand correctly what you are trying to do, just put a constraint on T:
public static T Recreate<T>() where T : RadControl, new() {
// etc.
}
You might have to use double dispatch and define
public static RadControl GetSettings(this RadControl control) {
}
which will invoke the appropriate GetSettings method.
No, Jason's answer is the cleaner way to go. The accepted solution killed the type safety and made use of generics pointless. You could switch to generic-less design (having a RadControlFactory) and had the job done.

Casting generic object array to two types

I've got a method that receives an Object[] and then performs actions on that array.
At first I was passing in this array as an IEnumerable<T> however the T can be of two different types.
The T's will always have the same properties, even thought they're different types.
Is it possible to cast to a a type at runtime so that I can used the properties i know each one will contain?
So where as it's possible to do:
var dataObject = (IEnumerable<T>) dataArray;
Is it somehow possible to do:
var dataObject = (dataArray.GetType()) dataArray;
Are you able to modify the source code of the two T types? If so then you could make both of them either (a) inherit from a common base class or (b) implement a common interface.
Edit following comments...
To accomodate different types for the ID property you could use explicit interface implementation. This would allow you to expose the second object's ID as an Int64 when accessed via the common interface. (The ID property would remain accessible as an Int32 when not accessed through the interface.)
Unfortunately the explicit interface implementation will require more changes to your original types.
void YourMethod(IEnumerable<ICommonToBothTypes> sequence)
{
foreach (var item in sequence)
{
Console.WriteLine(item.ID);
}
}
// ...
public interface ICommonToBothTypes
{
long ID { get; }
}
public class FirstType : ICommonToBothTypes
{
public long ID
{
get { return long.MaxValue; }
}
}
public class SecondType : ICommonToBothTypes
{
// the real Int32 ID
public int ID
{
get { return int.MaxValue; }
}
// explicit interface implementation to expose ID as an Int64
long ICommonToBothTypes.ID
{
get { return (long)ID; }
}
}
You can just create it as an interface and have both of those classes implement the interface. Then take Interface[] as the parameter instead of Object and you avoid casting all together.
If the two objects in the array derive from the same base type (inheritance) then you can box all the objects in your array as base class objects and you can use them with no knowledge of which particular object it might be.
See here for Boxing and Unboxing information from Microsoft
This is in essence what polymorphism is about, handling objects with a common interface.
Either inheritance from the same base class or creating an interface that both objects support will suit in this case. You will then be able to specifically define your array with either the base class type or the interface type, rather than "object".
If it's impossible to have the different classes all inherit the same interface, you can get all the properties defined in an object as a collection and then their value through key lookup where the key is the name of the property. I'd implement this as extension methods like so:
public static Dictionary<string, object> GetProperties<T>(this T instance)
where T : class
{
var values = new Dictionary<string, object>();
var properties =
instance.GetType().GetProperties(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.GetProperty);
foreach (var property in properties)
{
var accessors = property.GetAccessors();
if ((accessors == null) || (accessors.Length == 0))
continue;
string key = property.Name;
object value = property.GetValue(instance, null);
values.Add(key, value);
}
return values;
}
Then you can just do like this to get the property values:
void DoStuff(object[] objects)
{
foreach (var o in objects)
{
var properties = o.GetProperties();
var value = properties["PropertyName"];
}
}
It will all be untyped and you'll break things when renaming properties if you forget to also rename the lookup keys in the consuming code, but otherwise, this should work fine. However, the best solution is undoubtedly the one suggested by Luke (using interfaces).
If you have access to the sourcecode defining the two element types
You should introduce a new interace containing the common properties and let the other two interfaces inherit from your new base interface.
In your method you then use IEnumerable.Cast(TResult) to cast all elements to the common interface:
var dataObject = dataArray as IEnumerable;
if (dataObject != null)
{
var data = dataObject.Cast<ICommonBase>()
// do something with data
}
If you can't modify the sourcecode defining the two element types:
Use the IEnumerable.OfType() to filter elements based on their known types, effectively creating two strongly typed collections. Next perform the same operations with each of them (most verbose approach).
var dataObject = dataArray as IEnumerable;
if (dataObject != null)
{
var a = dataObject.OfType<InterfaceA>()
// do something with a
var b = dataObject.OfType<InterfaceB>()
// do the same with b
}
A reference of the functions used can be found on msdn.
If you want to avoid code duplication your only chance will be to use something called duck typing.Phil Haack has a great article on it.
The idea is to introduce a new interface that contains the common elements. You then duck-type the array elements, effectively making them comply to the new interface at runtime.
The last option would be using reflection and extracting property infos by common names and then access each elements data. This is the slowest and IMHO most cumbersome approach.

Categories