Why reinvent the wheel? Use Castle DynamicProxy2

Sep 26, 2009 at 9:49 PM
Edited Sep 26, 2009 at 9:54 PM

But even if you did not,  I refactored this into what I think is more flexible due to your lack of Generic Type CovarianceL

http://www.castleproject.org/dynamicproxy/index.html

 

Just for kicks I moved your code in that direction, but none of this needs to be here really, and no code is far better than even 1 line here as you get a multi-year highest quality library and source access. I do not know that spec your implementing but your IMPLEMENTATION of the concepts appears to be a lot of code that should not exist, which I hope you agree is good to know.

internal static class Support
    {
        internal static object ToProxyInstance(this Type t)

        {
            return t.ToProxy().CreateFactoryNonGeneric.CreateInstance();
        }

        private static IDynamicType ToProxy(this Type t)

        {
            var tG = typeof (DynamicType<>);


            var rNew = tG.MakeGenericType(new[] {t});

            return (IDynamicType) Activator.CreateInstance(rNew, t.Name, t.DerivePropertyTypes());
        }
    }

 

 

Your static class adds extension methood support as such:

 

public static class InterfaceSupport
    {
        public static IPropertyType[] DerivePropertyTypes(params Type[] interfaceTypes)
        {
            if (interfaceTypes == null) throw new ArgumentNullException("interfaceTypes");

            var propertyTypes = new List<IPropertyType>();
            foreach (var interfaceType in interfaceTypes)
            {
                propertyTypes.AddRange(DerivePropertyTypes(interfaceType));
            }

            return propertyTypes.ToArray();
        }

        public static IPropertyType[] DerivePropertyTypes(this Type interfaceType)
        {
            if (interfaceType == null) throw new ArgumentNullException("interfaceType");
            if (!interfaceType.IsInterface)
                throw new ArgumentException(SR.InterfaceTypeExpected(interfaceType), "interfaceType");

            var propertyInfos = FindProperties(interfaceType);
            return CreatePropertyTypes(propertyInfos);
        }

        private static IEnumerable<PropertyInfo> FindProperties(this Type interfaceType)
        {
            if (interfaceType == null) throw new ArgumentNullException("interfaceType");
            if (!interfaceType.IsInterface)
                throw new ArgumentException(SR.InterfaceTypeExpected(interfaceType), "interfaceType");

            var propertyInfos = new List<PropertyInfo>();

            propertyInfos.AddRange(interfaceType.GetProperties(BindingFlags.Public | BindingFlags.Instance));

            // inherited interfaces
            foreach (var parentInterfaceType in interfaceType.GetInterfaces())
            {
                propertyInfos.AddRange(FindProperties(parentInterfaceType));
            }

            return propertyInfos;
        }

        private static IPropertyType[] CreatePropertyTypes(this IEnumerable<PropertyInfo> propertyInfos)
        {
            if (propertyInfos == null) throw new ArgumentNullException("propertyInfos");

            var propertyTypeGenericType = typeof (PropertyType<>);

            var propertyTypes = new List<IPropertyType>();
            foreach (var propertyInfo in propertyInfos)
            {
                var propertyTypeType = propertyTypeGenericType.MakeGenericType(propertyInfo.PropertyType);
                var propertyType = (IPropertyType) Activator.CreateInstance(propertyTypeType, propertyInfo.Name);
                propertyTypes.Add(propertyType);
            }

            return propertyTypes.ToArray();
        }
    }

And with all tests still passing here is an example of one:

 


        [Test]
        public void TestBenchmarks()
        {
            var benchmark = (IBenchmark) typeof (IBenchmark).ToProxyInstance();
            var instrumentBenchmarkConstituent = (IInstrumentBenchmarkConstituent) typeof (IInstrumentBenchmarkConstituent).ToProxyInstance();

 
            instrumentBenchmarkConstituent.Benchmark = benchmark;
            instrumentBenchmarkConstituent.Weighting = 100;
        }

 

In refactoring this it was immediately apparant you should not redo what they did so well (NHibernate is critically dependant on it for things like lazy collections).

 

Damon

 

Coordinator
Sep 27, 2009 at 6:36 PM

Hi Damon

I agree that Castle, Spring, Linfu et al, are superior for producing proxied types. I uses these on a daily basis :-)

However, that isn't the point of what I am attempting to do in NAom. Perhaps the samples confused the issue, so let me explain.

Essentially, the purpose of NAom is to produce entirely dynamic POCO's at runtime. The DynamicType and PropertyType classes provide the mechanism for defining a type and it's properties.

At runtime, this "meta-data" is used to produce an "entity" class (via Reflection.Emit) and a corresponding factory type which allows for the creation of instances.

The attribute type, plus extension methods, provide type safe access to the dynamic properties and without the need for "string" names.

In the examples (and tests) I also used interfaces which have corresponding properties to that of the dynamic type.

In my experience, mostly in financial analytics type applications, there is usually a notion of well-known entities and their attributes, together with client defined/specific ones.

In this way, having an interface define the elements that are known, the programmer can deal with something more concrete in code, at the same time, supporting the dynamic nature of the object model.

Also, a non-sealed concrete type can be used as the basis of the dynamic type (i.e. will inherit from), if additional behavior, than that of a POCO, is required.  

 

The project is incomplete, as I haven't gotten to higher-level aspects of the framework, such as defining the type meta-data in terms of EntityTypes, AttributeTypes, Entities and Attributes as per the AOM pattern.

At this stage, the "guts" of the dynamic type and it's generation is complete, and a prototype application, which illustrates one possible implementation on top of a SQL database, is supplied.

 

Let me know if you need any further information.

vSv

 

Sep 28, 2009 at 4:08 AM

I get it. That makes 100% sense, however I am still wondering if you might benefit from getting proxies on slightly lower level type abstractions?  No idea.... You would have done it clearly if it made sense.

 That is something I believe the work of the RIA project at Microsoft is really innovating around  but of course they are implementation focused where this seems to be more a conceptial validation? Are you intending to use this work via adapters to ORM technology?

 

Nice work by any standard in what I have seen. You know .NET/CLR internals at an impressive level.  I was only suprised to not see this dominated by say a central expression parser-linq provider but no dount there are drivers where that does not help.

 

Thanks,

Damon

Coordinator
Sep 28, 2009 at 7:26 AM

Yes, the plan is to use an ORM technology. The NAom.DAL prototype is built using Linq2Sql, and uses some "magic" to convert the property type expressions to the underlying property at runtime.

var instrumentList1 =
  from e in instrumentRepository.GetAll()
  where e.GetProperty<IEntity, decimal?>(marketCapitalization) > 0  && 
        e.GetProperty<IEntity, bool?>(listedIndicator) == true
  select e;

I have also prototyped extensively using NHibernate + FluentNHibernate quite successfully and plan to add this implementation to the project when I have time.

I'll take a look at the RIA project.

Thanks

vSv