Get base class hierarchy methods with IMetaDataImport EnumMethods - c#

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).

Related

InvalidCastException while casting to defined Type C#

I have a Dictionary containing strings as keys, and objects as values in an abstract class.
I have two classes deriving from this abstract class.
One of the deriving classes works perfectly, all configurations and items are loaded and retrievable without issues.
However, the other class is giving me headaches.
When I try to get an object of type "Domain"; I get an invalid cast exception, although I am adding the value to the dictionary as said type.
Here is the code:
public sealed class UserDomainConfig: ConfigParser {
public UserDomainConfig(string configFilePath) : base(configFilePath) { }
public Domain GetConfig(string key) => GetConfig<Domain>(key);
public override bool LoadConfigs() {
return base.LoadConfigs();
}
public UserDomainConfig SetConfig(string key, Domain value) {
base.SetConfig(key, value);
return this;
}
}
public abstract class ConfigParser: IConfig {
/* Snip */
/// <summary>
/// Gets the config.
/// </summary>
/// <returns>The config.</returns>
/// <param name="key">Key.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public virtual T GetConfig<T>(string key) {
object output = null;
try {
if (!configs.TryGetValue(key, out output))
return default(T);
//return (T)output;
//return output as T;
// This is where the exception is occurring.
// I've tried multiple solutions to try to remedy this issue.
return (T)Convert.ChangeType(output, typeof(T));
} catch (InvalidCastException ex) {
logger.Error($"Failed to cast config { key }!");
}
return default(T);
}
/// <summary>
/// Sets the config.
/// </summary>
/// <returns>The config.</returns>
/// <param name="key">Key.</param>
/// <param name="value">Value.</param>
/// <typeparam name="T">The 1st type parameter.</typeparam>
public virtual IConfig SetConfig<T>(string key, T value) {
if (KeyExists(key))
configs.Remove(key);
configs.Add(key, value);
return this;
}
Any ideas on how to fix this, and/or why this isn't working in the first place, although it works like a charm with strings, bools, and ints?
The Convert class only supports simple types, known by .NET, like Int32, String, DateTime. It does not support user defined or complex types like Domain. If you try to convert something to a not-supported type, the method Convert.ChangeType throws an InvalidCastException. The only exception is that it will work if the Original value (output) is already of that desired type; than no actual conversion is needed.
For more information, read: https://msdn.microsoft.com/en-us/library/dtb69x08(v=vs.110).aspx
If you are certain the stored value is of the type Domain, than log more information. Something like this:
logger.Error($"Failed to cast config { key } of type { output.GetType() } to type { typeof(T) }!");
This way you can verify your claim that both types are the same.

Attributes and classes

I'm searching to how can I know inside an attribute definition if the class I apply the attribute to, has another attribute
Example:
[My1Attribute]
public class MyClass
{
[My2Attribute]
int aux{get;set;}
}
internal sealed class My1Attribute : Attribute
{
public My1Attribute
{
// How can I Know if 'MyClass' has My2Attribute applied ???
}
}
The attribute itself will not know about the class to which it's attached. You will need to use some other service/helper function/whatever to pair them up.
However, you might find the following useful:
public static bool HasAttribute<T, TAttribute>() where TAttribute : Attribute
{
return typeof (T).GetCustomAttributes(typeof (TAttribute), true).Any();
}
Edit: For finding attributes on member fields
/// <summary>
/// Returns all the (accessible) fields or properties that for a given type that
/// have the "T" attribute declared on them.
/// </summary>
/// <param name="type">Type object to search</param>
/// <returns>List of matching members</returns>
public static List<MemberInfo> FindMembers<T>(Type type) where T : Attribute
{
return FindMembers<T>(type, MemberTypes.Field | MemberTypes.Property);
}
/// <summary>
/// Returns all the (accessible) fields or properties that for a given type that
/// have the "T" attribute declared on them.
/// </summary>
/// <param name="type">Type object to search</param>
/// <returns>List of matching members</returns>
public static List<MemberInfo> FindMembers<T>(Type type, MemberTypes memberTypesFlags) where T : Attribute
{
const BindingFlags FieldBindingFlags = BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public;
List<MemberInfo> members = new List<MemberInfo>();
members.AddRange(type.FindMembers(
memberTypesFlags,
FieldBindingFlags,
HasAttribute<T>, // Use delegate from below...
null)); // This arg is ignored by the delegate anyway...
return members;
}
public static bool HasAttribute<T>(MemberInfo mi) where T : Attribute
{
return GetAttribute<T>(mi) != null;
}
public static bool HasAttribute<T>(MemberInfo mi, object o) where T : Attribute
{
return GetAttribute<T>(mi) != null;
}
In this instance, you would need to define your rules about how you determine what members you are going to check. In your example, you're using the attributed decorated on a property, so given that you have an instance of Type for MyClass (e.g. typeof(MyClass)), you can grab the properties:
var property = type.GetProperty("aux", BindingFlags.Instance | BindingFlags.NonPublic);
if (property.IsDefined(typeof(My1Attribute)))
{
// Property has the attribute.
}
(This is assuming you actually want to grab that non-public instance property, if not adjust your BindingFlags).
If you actually want to use the attribute:
var attib = property.GetCustomAttributes(typeof(My1Attribute), false)[0];
// Do something with the attribute instance.
Have you tried Reflection?, plus here's a related question that you might find helpful: How to check if C# class has security attribute used
I am guessing you mean in general find out if any class with MyAttribute1 has My2Attribute (rather than specifically MyClass). The only way I can think of doing it is getting a list of all classes from reflection and iterating through them checking which ones have Attribute1 and then check if they have Attribute2.
I don't think you can do anything clever like automatically retrieve a list of classes with current attribute.

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.

protobuf-net inheritance

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();
}
}

How do i use Activator.CreateInstance with strings?

In my reflection code i hit a problem with my generic section of code. Specifically when i use a string.
var oVal = (object)"Test";
var oType = oVal.GetType();
var sz = Activator.CreateInstance(oType, oVal);
Exception
An unhandled exception of type 'System.MissingMethodException' occurred in mscorlib.dll
Additional information: Constructor on type 'System.String' not found.
I tried this for testing purposes and it occurs in this single liner too
var sz = Activator.CreateInstance("".GetType(), "Test");
originally i wrote
var sz = Activator.CreateInstance("".GetType());
but i get this error
Additional information: No parameterless constructor defined for this object.
How do i create a string using reflection?
Keep in mind that the string class is immutable. It cannot be changed after it is created. That explains why it doesn't have a parameterless constructor, it could never generate a useful string object other than an empty string. That's already available in the C# language, it is "".
Same reasoning applies for a string(String) constructor. There is no point in duplicating a string, the string you'd pass to the constructor is already a perfectly good instance of the string.
So fix your problem by testing for the string case:
var oType = oVal.GetType();
if (oType == typeof(string)) return oVal as string;
else return Activator.CreateInstance(oType, oVal);
You are trying to do this :
var sz = new string();
Try to compile it, you will understand your error.
You may try :
var sz = Activator.CreateInstance(typeof(string), new object[] {"value".ToCharArray()});
But it looks useless, you should directly use value...
It looks like you're trying to call a constructor which just takes a string - and there isn't such a constructor. If you've already got a string, why are you trying to create a new one? (When you didn't provide any further arguments, you were trying to call a parameterless constructor - which again, doesn't exist.)
Note that typeof(string) is a simpler way to get a reference to the string type.
Could you give us more information about the bigger picture of what you're trying to do?
String actually has no constructor that takes a string as input. There is a constructor that takes a char array so this should work:
var sz = Activator.CreateInstance ("".GetType (), "Test".ToCharArray ());
This is what I use in my projects. As far as needing to create an instantiation of a type of object and not knowing at design time, is rather normal for me. Perhaps you are cycling through object properties and you want to instantiate all of them dynamically. I have many times needed to create then assign values to non instantiated POCO objects... with the below code you can use a string value stored in the DB to instantiate an object as well or instantiate an object stored in a library that is referencing your library - so you can bypass circular reference errors as well... Hope it helps.
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
/// <summary>
/// Instantiates an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// returns instantiated object
/// </summary>
/// <param name="typeName"></param>
/// <returns></returns>
public static object Create(string typeAssemblyQualifiedName)
{
// resolve the type
Type targetType = ResolveType(typeAssemblyQualifiedName);
if (targetType == null)
throw new ArgumentException("Unable to resolve object type: " + typeAssemblyQualifiedName);
return Create(targetType);
}
/// <summary>
/// create by type of T
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public static T Create<T>()
{
Type targetType = typeof(T);
return (T)Create(targetType);
}
/// <summary>
/// general object creation
/// </summary>
/// <param name="targetType"></param>
/// <returns></returns>
public static object Create(Type targetType)
{
//string test first - it has no parameterless constructor
if (Type.GetTypeCode(targetType) == TypeCode.String)
return string.Empty;
// get the default constructor and instantiate
Type[] types = new Type[0];
ConstructorInfo info = targetType.GetConstructor(types);
object targetObject = null;
if (info == null) //must not have found the constructor
if (targetType.BaseType.UnderlyingSystemType.FullName.Contains("Enum"))
targetObject = Activator.CreateInstance(targetType);
else
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Constructor not found");
else
targetObject = info.Invoke(null);
if (targetObject == null)
throw new ArgumentException("Unable to instantiate type: " + targetType.AssemblyQualifiedName + " - Unknown Error");
return targetObject;
}
/// <summary>
/// Loads the assembly of an object. Must pass PropertyType.AssemblyQualifiedName for factory to operate
/// Returns the object type.
/// </summary>
/// <param name="typeString"></param>
/// <returns></returns>
public static Type ResolveType(string typeAssemblyQualifiedName)
{
int commaIndex = typeAssemblyQualifiedName.IndexOf(",");
string className = typeAssemblyQualifiedName.Substring(0, commaIndex).Trim();
string assemblyName = typeAssemblyQualifiedName.Substring(commaIndex + 1).Trim();
if (className.Contains("[]"))
className.Remove(className.IndexOf("[]"), 2);
// Get the assembly containing the handler
Assembly assembly = null;
try
{
assembly = Assembly.Load(assemblyName);
}
catch
{
try
{
assembly = Assembly.LoadWithPartialName(assemblyName);//yes yes this is obsolete but it is only a backup call
}
catch
{
throw new ArgumentException("Can't load assembly " + assemblyName);
}
}
// Get the handler
return assembly.GetType(className, false, false);
}

Categories