I Work on c#/Code first
I've a Parent Class
abstract public class form_base {}
and severals differents childs class.
Here one of them
public class form_Frais : form_base {
}
I've a view with all form_base, but when i click on one, I open a common template.
I just need change the mapping according to child type in changing the controler/Function by an URL
Then In my form_base
I had this :
public T Cast<T>(object o)
{
return (T)o;
}
public dynamic converttt(Type LeTyp)
{
MethodInfo castMethod = GetType().GetMethod("Cast").MakeGenericMethod(new[] { LeTyp });
dynamic castedObject = castMethod.Invoke(Activator.CreateInstance(LeTyp), new object[] { this });
return castedObject;
}
I've split my project in 2 part (engine/Web) My classes are define in engine
My problem is to fill my list of all form_base in web part.
I use this function in controler part
public ActionResult demandeur()
{
object model;
model = new { formsList = (from f in CurrentDBContext.forms_base select f).ToList().getCardModel(false) };
}
return View("demandeur", model);
}
And In web I create extension methods (I won't see in engine part)
public static partial class extensions
{
public static List<formListItem> getCardModel(this List<form_base> items, bool envalidation)
{
List<formListItem> model = new List<formListItem>();
if (items != null && items.Count > 0)
{
foreach (var item in items)
{
Type LeTyp = item.GetType().BaseType;
dynamic castedObject = item.converttt(LeTyp);//Pb here not good type : System.Data.Entity.DynamicProxies.form_Frais_353DEAA5...' ne contient pas de définition pour 'getCardModel''
model.Add(castedObject.getCardModel(envalidation));
}
}
return model;
}
public static formListItem getCardModelBase(this form_base f)
{
formListItem model = new formListItem();
model.id = f.id;
model.libelle = f.title;
model.libelleType = f.formType.title;
model.libelleStatut = f.StatutInterneLibelle;
model.demandeur = f.demandeur.fullName;
model.idtype = f.formType.id;
return model;
}
public static formListItem getCardModel(this form_Frais form, bool envalidation)
{
formListItem model = ((form_base)form).getCardModelBase();
model.URL = "/forms/NoteFrais/InitForm"; //The good URL
model.envalidation = envalidation;
return model;
}
}
I try to put all in extension part like that:
public static T Cast<T>(object o)
{
return (T)o;
}
public static List<formListItem> getCardModel(this List<form_base> items, bool envalidation)
{
List<formListItem> model = new List<formListItem>();
if (items != null && items.Count > 0)
{
foreach (var item in items)
{
Type LeTyp = item.GetType().BaseType;
MethodInfo castMethod = item.GetType().BaseType.GetMethod("Cast").MakeGenericMethod(new[] { LeTyp });
dynamic castedObject = castMethod.Invoke(null, new object[] { item });
model.Add(castedObject.getCardModel(envalidation));
}
}
return model;
}
public static formListItem getCardModelBase(this form_base f)
{
formListItem model = new formListItem();
model.id = f.id;
model.libelle = f.title;
model.libelleType = f.formType.title;
model.libelleStatut = f.StatutInterneLibelle;
model.demandeur = f.demandeur.fullName;
model.idtype = f.formType.id;
return model;
}
But I've error in item.GetType().BaseType.GetMethod("Cast").MakeGenericMethod(new[] { LeTyp }); cause GetMethod("Cast") return null
All my research come from here
UPDATE
In resume, In first try, I've problem of type class return dynamicproxy...
And in static version, I can't find method Cast..
I try
MethodInfo[] methodInfos = LeTyp.GetMethods(BindingFlags.Public | BindingFlags.Static);
But My array is empty... then my problem in static version will be hwo save correctly my Case function??? and use it in extension method
UPDATE 3
I find the problem in static mode
I need tu put Cast function in note_frais class
and use it
Type LeTyp = item.GetType().BaseType;
//MethodInfo[] methodInfos = LeTyp.GetMethods(BindingFlags.Public | BindingFlags.Static);
MethodInfo MI = LeTyp.GetMethod("Cast");//<T>.getMethod(cast)
MI = MI.MakeGenericMethod(typeof(form_base));
dynamic t = MI.Invoke(null, new object[] { item });
model.Add(t.getCardModel(envalidation));
But now I've same pb in 2 parts :
//Pb here not good type : System.Data.Entity.DynamicProxies.form_Frais_353DEAA5...' ne contient pas de définition pour 'getCardModel''
Thanks for your help? I read lot of things but now I'm completly lost.
Instead of:
GetMethod("Cast")
...try this overload:
GetMethod("Cast", new Type[] { typeof(Object) })
More observations...
The Cast<T> method of class form_base is not static. (See above to get this one.)
The class form_base doesn't define any public static methods.
(Side note, I'm not sure why the class extensions is defined as partial.)
The Cast<T> method in class extensions is static, but is not an extension method.
To get this one, you can use this overload, on type extensions:
typeof(extensions).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(Object) }, null)
If you did define the Cast<T> extension method in class extensions:
public static partial class extensions {
public static T Cast<T>(this form_base b, object o) {/*…*/}
}
...then you could get it with the same overload on type extensions, by modifying the types argument:
typeof(extensions).GetMethod("Cast", BindingFlags.Public | BindingFlags.Static, null, new Type[] { typeof(form_base), typeof(Object) }, null)
Finally... With a simple sample it's good
using System;
using System.Collections.Generic;
using System.Reflection;
namespace ConsoleApp1
{
abstract public class form_base
{
public Guid Guid { get; set; }
}
public class form_Frais : form_base
{
public int MonInt { get; set; }
public static T Cast<T>(object o)
{
return (T)o;
}
}
public class form_Avoir : form_base
{
public int MonInt { get; set; }
public static T Cast<T>(object o)
{
return (T)o;
}
}
public static class extensions
{
public static int GetCardModel(this form_Avoir form)
{
return form.MonInt * 100;
}
public static int GetCardModel(this form_Frais form)
{
return form.MonInt * form.MonInt;
}
}
public class TOTO
{
public static int GetCardModel(form_Avoir form)
{
return form.MonInt * 100;
}
public static int GetCardModel(form_Frais form)
{
return form.MonInt * form.MonInt;
}
}
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hello World!");
form_Frais nf = new form_Frais();
nf.Guid = Guid.NewGuid();
nf.MonInt = 2;
List<form_base> lst = new List<form_base>();
//MethodInfo[] methodInfos = typeof(form_base).GetMethods(BindingFlags.Public | BindingFlags.Static);
lst.Add(nf);
form_Avoir av = new form_Avoir();
av.Guid = Guid.NewGuid();
av.MonInt = 5;
lst.Add(av);
foreach (dynamic f in lst)
{
Console.WriteLine(TOTO.GetCardModel(f)); // OK
//Type LeTyp = f.GetType();
//MethodInfo MI = LeTyp.GetMethod("Cast");//<T>.getMethod(cast)
//MI = MI.MakeGenericMethod(typeof(form_base));
//dynamic t = MI.Invoke(null, new object[] { f });
//Console.WriteLine(t.GetCardModel());// Error
}
}
}
}
My error was to thought that extension methods was include in object. In fact not. It seems but not really. I just change with a method with parameter instead of extension
How can i get the Key for a specific MyData.Name value?
I dont need to modify the Dictionary
This is the given situation and i need to match "Server" to 1L
public class MyBase
{
protected struct MyData
{
public string Name;
}
}
public class MyClass : MyBase
{
private readonly Dictionary<ulong, MyBase.MyData> m_Data = new Dictionary<ulong, MyBase.MyData>();
public MyClass()
{
m_Data.Add(1L, new MyData { Name = "Server" });
}
}
public class MyMulti
{
public static MyClass myClass = new MyClass();
}
public class Test
{
Type MyDataType = typeof(MyBase).GetNestedType("MyData", BindingFlags.Instance | BindingFlags.NonPublic);
object m_Data = typeof(MyClass).GetField("m_Data", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MyMulti.myClass);
// How can i get the Key for a specific MyData.Name value?
}
I actualy just found an easy way to do so:
var m_Data = typeof(MyClass).GetField("m_Data", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(MyMulti.myClass) as IDictionary;
foreach (var pair in m_Data.Keys)
{
Console.WriteLine(pair + " = " + m_Data[pair].GetType().GetField("Name").GetValue(m_Data[pair]));
}
Consider the following C# class declaration:
public class MyClass {
private enum Colours { Red, Green, Blue }
}
Which is sat in a separate class library/DLL.
Given just the typeof(MyClass) object (System.Type), is there any way to check if the class contains an enum called Colours at runtime and if so return it's corresponding System.Type object?
What I'm trying to do is write some generic code that's given the type of a class and determine if contains a specifically named enum inside and then query the values in the enum.
I know how to use Reflection to query things like GetFields, GetProperties etc. but there isn't a GetClasses or GetEnums method in System.Type.
I suspect this kind of information is in the assembly?
Just do:
var res = typeof(MyClass).GetNestedType("Colours", BindingFlags.NonPublic);
Test res != null to see if such type exists.
Then test res.IsEnum to see if the nested type is an enum.
Addition: If the nested type is occasionally nested public, use BindingFlags.NonPublic | BindingFlags.Public instead.
I came up with following two methods:
public class MyClass {
private enum Colours { Red, Green, Blue }
private class Inner {
private enum Colours { Black, White }
}
}
class Program {
static void Main(string[] args) {
Type coloursType;
// 1. enumerator
coloursType = typeof(MyClass).EnumerateNestedTypes()
.Where(t => t.Name == "Colours" && t.IsEnum)
.FirstOrDefault();
// 2. search method
coloursType = typeof(MyClass).FindNestedType(t => t.Name == "Colours" && t.IsEnum);
if(coloursType != null) {
Console.WriteLine(string.Join(", ", coloursType.GetEnumNames()));
} else {
Console.WriteLine("Type not found");
}
Console.ReadKey();
}
}
public static class Extensions {
public static IEnumerable<Type> EnumerateNestedTypes(this Type type) {
const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic;
Queue<Type> toBeVisited = new Queue<Type>();
toBeVisited.Enqueue(type);
do {
Type[] nestedTypes = toBeVisited.Dequeue().GetNestedTypes(flags);
for(int i = 0, l = nestedTypes.Length; i < l; i++) {
Type t = nestedTypes[i];
yield return t;
toBeVisited.Enqueue(t);
}
} while(toBeVisited.Count != 0);
}
public static Type FindNestedType(this Type type, Predicate<Type> filter) {
const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic;
Type[] nestedTypes = type.GetNestedTypes(flags);
foreach(var nestedType in nestedTypes) {
if(filter(nestedType)) {
return nestedType;
}
}
foreach(var nestedType in nestedTypes) {
Type result = FindNestedType(nestedType, filter);
if(result != null) {
return result;
}
}
return null;
}
}
var types = typeof(MyClass).Assembly.DefinedTypes;
foreach (var type in types)
{
Console.WriteLine(type.Name);
}
Output:
MyClass
Colours
I'm trying to generate classes at runtime that implement property getters with a body that calls a method on the generated class's base class. Here's an example of a simple interface, along with a hand-written implementation that I'm trying to duplicate and the base class.
public interface IGenerated : IBase { decimal Property1 { get; } }
public class GeneratedByHand : ImplBase<IGenerated> {
public decimal Property1 { get { return Get(s => s.Property1); } }
}
public interface IBase { string _KeyPrefix { get; set; } }
public abstract class ImplBase<T> : IBase
where T : IBase
{
public virtual string _KeyPrefix { get; set; }
protected virtual TResult Get<TResult>(Expression<Func<T, TResult>> property) {
return GetValue<TResult>(GetPropertyName(property));
}
private string GetPropertyName<TResult>(Expression<Func<T, TResult>> property) {
return ""; // reflection stuff to get name from property expression goes here
}
private TResult GetValue<TResult>(string keyPart) {
return default(TResult); // does something like: return ReallyGetValue<TResult>(_KeyPrefix + keyPart);
}
}
I have a working implementation of the generator that emits IL to build the method, but if I can do it with Expressions I think that will be easier to expand and maintain. I will need to look for custom attributes on the property definitions and use that to call different method overloads on the base class in the property implementations.
Here's where I've gotten building an expression for the property get implementation. What I don't really understand is building the Call expression, if I'm setting it up correctly to do the equivalent of this.Get() or base.Get(). Right now it throws a System.ArgumentException : Invalid argument value Parameter name: method at CompileToMethod
public void CreateExpressionForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var settingsParam = Expression.Parameter(interfaceType, "s");
var propGetterExpr = Expression.Property(settingsParam, property);
var propGetterExprFuncType = typeof(Func<,>).MakeGenericType(interfaceType, property.PropertyType);
var propGetterLambda = Expression.Lambda(propGetterExprFuncType, propGetterExpr, settingsParam);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
})
.First().MakeGenericMethod(property.PropertyType);
var getExprType = typeof(Expression<>).MakeGenericType(propGetterExprFuncType);
var getExprParam = Expression.Parameter(getExprType, "expression");
var getCallExpr = Expression.Call(Expression.Parameter(baseType, "inst"), baseGetMethodInfo, propGetterLambda);
var getFuncType = typeof(Func<,>).MakeGenericType(getExprType, property.PropertyType);
var propLambda = Expression.Lambda(getFuncType, getCallExpr, getExprParam);
propLambda.CompileToMethod(getBuilder);
}
I'm not really sure where to go from here. I've tried a few other variations of arguments to Expression.Call, but everything else had Call throwing exceptions for the parameters being the wrong types.
Here's a buildable version of all the sample code I'm working with, including the working IL emitter:
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using NUnit.Framework;
namespace ExpressionGenerationTest
{
[TestFixture]
public class UnitTests
{
[Test]
public void CreateAndSaveAssembly()
{
var implGenerator = new ImplBuilder();
var generatedType = implGenerator.CreateImplementation(typeof(IGenerated));
implGenerator.SaveAssembly();
}
}
public interface IBase { string _KeyPrefix { get; set; } }
public abstract class ImplBase<T> : IBase
where T : IBase
{
public virtual string _KeyPrefix { get; set; }
protected virtual TResult Get<TResult>(Expression<Func<T, TResult>> property) { return GetValue<TResult>(GetPropertyName(property)); }
private string GetPropertyName<TResult>(Expression<Func<T, TResult>> property) { return ""; } // reflection stuff to get name from property expression goes here
private TResult GetValue<TResult>(string keyPart) { return default(TResult); } // does something like: return ReallyGetValue(_KeyPrefix + keyPart);
}
public interface IGenerated : IBase { decimal Property1 { get; } }
public class GeneratedByHand : ImplBase<IGenerated> { public decimal Property1 { get { return Get(s => s.Property1); } } }
public class ImplBuilder
{
private const string _assemblyNameBase = "ExpressionGenerationTest.Impl";
public static ImplBuilder Default { get { return _default.Value; } }
private static readonly Lazy<ImplBuilder> _default = new Lazy<ImplBuilder>(() => new ImplBuilder());
private ConcurrentDictionary<Type, Type> _types = new ConcurrentDictionary<Type, Type>();
private AssemblyBuilder _assemblyBuilder = null;
private volatile ModuleBuilder _moduleBuilder = null;
private object _lock = new object();
private void EnsureInitialized()
{
if (_moduleBuilder == null) {
lock (_lock) {
if (_moduleBuilder == null) {
_assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(_assemblyNameBase), AssemblyBuilderAccess.RunAndSave);
_moduleBuilder = _assemblyBuilder.DefineDynamicModule(_assemblyBuilder.GetName().Name, _assemblyNameBase + ".dll");
}
}
}
}
public void SaveAssembly() { _assemblyBuilder.Save(_assemblyNameBase + ".dll"); }
public TSettings CreateInstance<TSettings>() { return (TSettings)Activator.CreateInstance(_types.GetOrAdd(typeof(TSettings), CreateImplementation)); }
public void CreateImplementations(IEnumerable<Type> types) { foreach (var t in types) _types.GetOrAdd(t, InternalCreateImplementation); }
public Type CreateImplementation(Type interfaceType) { return _types.GetOrAdd(interfaceType, InternalCreateImplementation); }
private Type InternalCreateImplementation(Type interfaceType)
{
EnsureInitialized();
var baseType = typeof (ImplBase<>).MakeGenericType(interfaceType);
var typeBuilder = _moduleBuilder.DefineType(
(interfaceType.IsInterface && interfaceType.Name.StartsWith("I")
? interfaceType.Name.Substring(1)
: interfaceType.Name) + "Impl",
TypeAttributes.Public | TypeAttributes.Class |
TypeAttributes.AutoClass | TypeAttributes.AnsiClass |
TypeAttributes.BeforeFieldInit | TypeAttributes.AutoLayout,
baseType,
new [] {interfaceType});
foreach (var p in GetPublicProperties(interfaceType).Where(pi => pi.DeclaringType != typeof(IBase))) {
var iGet = p.GetGetMethod();
if (iGet != null) {
var getBuilder =
typeBuilder.DefineMethod(iGet.Name,
MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
p.PropertyType, Type.EmptyTypes);
//EmitILForGetMethod(getBuilder, interfaceType, baseType, p, iGet);
CreateExpressionForGetMethod(getBuilder, interfaceType, baseType, p, iGet);
typeBuilder.DefineMethodOverride(getBuilder, iGet);
}
}
var implementationType = typeBuilder.CreateType();
return implementationType;
}
public void CreateExpressionForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var settingsParam = Expression.Parameter(interfaceType, "s");
var propGetterExpr = Expression.Property(settingsParam, property);
var propGetterExprFuncType = typeof(Func<,>).MakeGenericType(interfaceType, property.PropertyType);
var propGetterLambda = Expression.Lambda(propGetterExprFuncType, propGetterExpr, settingsParam);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
})
.First().MakeGenericMethod(property.PropertyType);
var getExprType = typeof(Expression<>).MakeGenericType(propGetterExprFuncType);
var getExprParam = Expression.Parameter(getExprType, "expression");
var getCallExpr = Expression.Call(Expression.Parameter(baseType, "inst"), baseGetMethodInfo, propGetterLambda);
var getFuncType = typeof(Func<,>).MakeGenericType(getExprType, property.PropertyType);
var propLambda = Expression.Lambda(getFuncType, getCallExpr, getExprParam);
propLambda.CompileToMethod(getBuilder);
}
public void EmitILForGetMethod(MethodBuilder getBuilder, Type interfaceType, Type baseType, PropertyInfo property, MethodInfo getMethod)
{
var getGen = getBuilder.GetILGenerator();
var retVal = getGen.DeclareLocal(property.PropertyType);
var expParam = getGen.DeclareLocal(typeof(ParameterExpression));
var expParams = getGen.DeclareLocal(typeof(ParameterExpression[]));
getGen.Emit(OpCodes.Ldarg_0);
getGen.Emit(OpCodes.Ldtoken, interfaceType);
getGen.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
getGen.Emit(OpCodes.Ldstr, "s");
getGen.Emit(OpCodes.Call, typeof(Expression).GetMethod("Parameter", new [] {typeof(Type), typeof(string)}));
getGen.Emit(OpCodes.Stloc, expParam);
getGen.Emit(OpCodes.Ldloc, expParam);
getGen.Emit(OpCodes.Ldtoken, getMethod);
getGen.Emit(OpCodes.Call, typeof(MethodBase).GetMethod("GetMethodFromHandle", new [] {typeof(RuntimeMethodHandle)}, null));
getGen.Emit(OpCodes.Castclass, typeof(MethodInfo));
getGen.Emit(OpCodes.Call, typeof(Expression).GetMethod("Property", new[] {typeof(Expression), typeof(MethodInfo)}));
getGen.Emit(OpCodes.Ldc_I4_1);
getGen.Emit(OpCodes.Newarr, typeof(ParameterExpression));
getGen.Emit(OpCodes.Stloc, expParams);
getGen.Emit(OpCodes.Ldloc, expParams);
getGen.Emit(OpCodes.Ldc_I4_0);
getGen.Emit(OpCodes.Ldloc, expParam);
getGen.Emit(OpCodes.Stelem_Ref);
getGen.Emit(OpCodes.Ldloc, expParams);
var lambdaMethodInfo =
typeof(Expression).GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(x => {
var parameters = x.GetParameters();
return x.Name == "Lambda" &&
x.IsGenericMethodDefinition &&
parameters.Count() == 2 &&
parameters[0].ParameterType == typeof(Expression) &&
parameters[1].ParameterType == typeof(ParameterExpression[]);
}).FirstOrDefault();
var lambdaFuncType = typeof(Func<,>);
lambdaFuncType = lambdaFuncType.MakeGenericType(interfaceType, property.PropertyType);
lambdaMethodInfo = lambdaMethodInfo.MakeGenericMethod(lambdaFuncType);
getGen.Emit(OpCodes.Call, lambdaMethodInfo);
var baseGetMethodInfo =
baseType.GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
.Where(m => {
var parameters = m.GetParameters();
return m.Name == "Get" &&
parameters != null && parameters.Count() == 1 && parameters[0].ParameterType != typeof(string);
}).FirstOrDefault();
baseGetMethodInfo = baseGetMethodInfo.MakeGenericMethod(property.PropertyType);
getGen.Emit(OpCodes.Callvirt, baseGetMethodInfo);
getGen.Emit(OpCodes.Stloc_0);
var endOfMethod = getGen.DefineLabel();
getGen.Emit(OpCodes.Br_S, endOfMethod);
getGen.MarkLabel(endOfMethod);
getGen.Emit(OpCodes.Ldloc_0);
getGen.Emit(OpCodes.Ret);
}
// from http://stackoverflow.com/a/2444090/224087
public static PropertyInfo[] GetPublicProperties(Type type)
{
if (!type.IsInterface)
return type.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
var propertyInfos = new List<PropertyInfo>();
var considered = new List<Type>();
var queue = new Queue<Type>();
considered.Add(type);
queue.Enqueue(type);
while (queue.Count > 0) {
var subType = queue.Dequeue();
foreach (var subInterface in subType.GetInterfaces()) {
if (considered.Contains(subInterface))
continue;
considered.Add(subInterface);
queue.Enqueue(subInterface);
}
var typeProperties = subType.GetProperties(BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
var newPropertyInfos = typeProperties.Where(x => !propertyInfos.Contains(x));
propertyInfos.InsertRange(0, newPropertyInfos);
}
return propertyInfos.ToArray();
}
}
}
What I don't really understand is building the Call expression, if I'm setting it up correctly to do the equivalent of this.Get() or base.Get().
If you are calling a virtual method, then this.Get(), which accesses the most-derived override (which could even be defined in a descendant of the current class), uses the callvirt instruction. And it doesn't matter what type you reflect against to get the MethodInfo, because they all share the same virtual table slot.
To emit base.Get(), you must
use the call instruction
reflect against the base class type
Because callvirt does some extra things besides v-table lookup, including a null pointer check, the C# compiler uses it for all virtual and non-virtual calls, except those involving the base keyword.
In particular, anonymous delegates and lambdas can't make use of the base keyword, since only descendant types can make non-virtual calls to virtual methods (at least in verifiable code), and the lambda is actually hosted by a closure type.
So unfortunately for your use case, there's no way to express a base call using lambda notation or expression trees. Expression.CompileToMethod only generates callvirt. Well, that isn't exactly correct. It generates call for calls to static methods and instance methods of value types. But instance methods of reference types use only callvirt. You can see this in System.Linq.Expressions.Compiler.LambdaCompiler.UseVirtual
Thanks #hvd for confirming this based on comments found in the Microsoft Reference Source for UseVirtual
Take for example the below sample code:
public class TestMultipleAttributesAttribute : AttributeWithPriority
{
public string HelpMessage { get; set; }
}
public class Student
{
[TestMultipleAttributes(HelpMessage = "Student")]
public virtual string Name { get; set; }
}
public class SpecificStudent : Student
{
[TestMultipleAttributes(Priority = 100, HelpMessage = "SpecificStudent")]
public override string Name { get; set; }
}
Is there any way by reflection how I can get both the two instances of the TestMultipleAttributes for the same overriden property?
I tried the below code:
[Test]
public void testMultipleAttribs()
{
var property = typeof(SpecificStudent).GetProperties().FirstOrDefault(x => x.Name == "Name");
var attribList = property.Attributes; //returns none
var customAttribs = property.CustomAttributes.ToList(); //returns 1
var customAttribs2 = property.GetCustomAttributes(inherit: true);// returns 1
int k = 5;
}
One solution that came in mind is to find the property.DeclaringType, and repeating the process , and get the attributes for it. However, I don't find it an elegant way to do this and was wondering if there is a better way.
You have only one attribute named TestMultipleAttributes and you overwrote it.The attribute have more than one property (Priority and HelpMessage) its working correctly.
You can create more "really" attributes like so StudentAttribute and SpecificStudentAttribute.
I don't know...this is relatively elegant (though I'm sure I'm missing at least one special case). It should enumerate all the custom attributes on an overridden or virtual property in the inheritance chain in nearest-first order:
public static IEnumerable<Attribute> AllAttributes( PropertyInfo pi )
{
if ( pi != null )
{
// enumerate all the attributes on this property
foreach ( object o in pi.GetCustomAttributes( false ) )
{
yield return (Attribute) o ;
}
PropertyInfo parentProperty = FindNearestAncestorProperty(pi) ;
foreach( Attribute attr in AllAttributesRecursive(parentProperty) )
{
yield return attr ;
}
}
}
private static PropertyInfo FindNearestAncestorProperty( PropertyInfo property )
{
if ( property == null ) throw new ArgumentNullException("property") ;
if ( property.DeclaringType == null ) throw new InvalidOperationException("all properties must belong to a type");
// get the property's nearest "ancestor" property
const BindingFlags flags = BindingFlags.DeclaredOnly
| BindingFlags.Public | BindingFlags.NonPublic
| BindingFlags.Static | BindingFlags.Instance
;
Type t = property.DeclaringType.BaseType ;
PropertyInfo ancestor = null ;
while ( t != null && ancestor == null )
{
ancestor = t.GetProperty(property.Name,flags) ;
t = t.BaseType ;
} ;
return ancestor ;
}