Showing posts with label reflection. Show all posts
Showing posts with label reflection. Show all posts

Thursday, October 11, 2018

Making the Dynamic Operator More ... Dynamic

So in F# you can (and have to if you want it) make a dynamic operator implementation.

Like so:
    let (?) (this : 'Source) (prop : string) : 'Result =
        let t : Type = this.GetType()
        let p : PropertyInfo = t.GetProperty(prop)
        if isNull p then failwithf "could not find prop %s" prop
        p.GetValue(this, null) :?> 'Result
Or dynamic setters even:
    let (?<-) (this: 'Source) (prop:string) (value: 'Value) =
        this.GetType().GetProperty(prop).SetValue(this,value,null)
Which are accessed by name not by string (even though the effect is like a magic string):
    type Test(code:string) = 
        member val Code = code with get,set
    let nakedTest : Test = Test("hello")
    let x : obj = box nakedTest
    let value : string = x?Code
    printfn "I found the property and retrieved the value, it was %s" value

Or the setter like: x?Code <- "dynamic"

Now what happens if I want part of that implementation to be variable, I want to pass different combinations of BindingFlag bits, and the keep the rest of the implementation the same?

Perhaps I want to access static or private properties, with different (?) implementations.

Well, it's possible!


    let makePropAccess (flags:BindingFlags) =
        let (?) (this : 'Source) (prop : string) : 'Result =
            let t = this.GetType()
            if isNull t then failwithf "bad getType"
            let p = t.GetProperty(prop,flags)
            if isNull p then failwithf"could not find prop %s" prop
            p.GetValue(this, null) :?> 'Result
        (?)
        
    let (?) = makePropAccess (BindingFlags.Public ||| BindingFlags.Instance) 
    let x = Test("Code")    
    x?Code
full LINQPad code at Github.com/ImaginaryDevelopment/LinqPad/LINQPad Queries/Reflection/F# dynamic operator implementation.linq

I wonder how (or if) you could even access this from C#

Thursday, November 13, 2014

Binding redirects at runtime

Hopfully the C# audience can read this F#, but this is how you would do it =)
// https://dotnetfiddle.net/UnS2vU
printfn "starting up"
open System
open System.Reflection

let RedirectAssembly shortName (targetVersion : Version) publicKeyToken = 
    let rec onResolveEvent = new ResolveEventHandler( fun sender evArgs ->
        let requestedAssembly = 
            AssemblyName(evArgs.Name)
        if requestedAssembly.Name <> shortName 
        then 
            printfn "redirect firing for %s" requestedAssembly.Name; Unchecked.defaultof<Assembly>
        else 
            printfn 
                "Redirecting assembly load of %s ,\tloaded by %s" 
                evArgs.Name 
                (if evArgs.RequestingAssembly = null then 
                     "(unknown)"
                 else 
                     evArgs.RequestingAssembly.FullName)
            requestedAssembly.Version <- targetVersion
            requestedAssembly.SetPublicKeyToken (AssemblyName(sprintf "x, PublicKeyToken=%s" publicKeyToken).GetPublicKeyToken())
            requestedAssembly.CultureInfo <- System.Globalization.CultureInfo.InvariantCulture
            AppDomain.CurrentDomain.remove_AssemblyResolve(onResolveEvent)
            Assembly.Load (requestedAssembly)
            )
    AppDomain.CurrentDomain.add_AssemblyResolve(onResolveEvent)
    
// sample usage
RedirectAssembly "FSharp.Core" (Version("4.3.1.0")) "b03f5f7f11d50a3a"

Wednesday, May 4, 2011

ObjectDumper extended

This should be functionally equivalent to Microsoft's version just my own refactorings to support extensibility: No behavior should be different.


using System;
using System.IO;
using System.Collections;
using System.Reflection;

namespace Utilities
{
/// 
/// From Microsoft's http://archive.msdn.microsoft.com/cs2008samples/
/// modified for extensibility
/// 
public class ObjectDumper
{

/// 
/// StaticWrite
/// 
/// public static void Write(object element)
{
Write(element, 0);
}
protected static TextWriter DefaultWriter=Console.Out;
/// 
/// Static Write
/// 
/// /// public static void Write(object element, int depth)
{
Write(element, depth, DefaultWriter);
}
/// 
/// Static Write
/// 
/// /// /// public static void Write(object element, int depth, TextWriter log)
{
var dumper = new ObjectDumper(depth) {_writer = log};
dumper.WriteObject(null, element);
}


private TextWriter _writer;
int _pos;
int _level;
readonly int _depth;

protected ObjectDumper(int depth)
{
_depth = depth;
}
protected ObjectDumper(int depth, TextWriter log):this(depth)
{
_writer = log;
}
/// 
/// MethodWrite
/// 
/// protected void WriteString(string s)
{
if (s != null)
{
_writer.Write(s);
_pos += s.Length;
}
}

protected virtual void WriteIndent()
{
for (int i = 0; i < _level; i++) _writer.Write("  ");
        }

        protected void WriteLine()
        {
            _writer.WriteLine();
            _pos = 0;
        }
        
        protected virtual void WriteTab()
        {
            WriteString("  ");
            while (_pos % 8 != 0) WriteString(" ");
        }
        protected  void DescendIfDepthAllows(Action doIfDescend)
        {
            if (_level < _depth)
            {
                _level++;
                doIfDescend();
                _level--;
               
            }
        }

        protected virtual  void WriteObject(string prefix, object element)
        {
            if (element == null || element is ValueType || element is string)
            {
                WriteIndent();
                WriteString(prefix);
                WriteValue(element);
                WriteLine();
            }
            else
            {
                var enumerableElement = element as IEnumerable;
                if (enumerableElement != null)
                {
                    WriteEnumerable(prefix, enumerableElement);
                }
                else
                {
                    WriteWithReflection(element, prefix);
                }
            }
        }

        protected virtual void WriteWithReflection(object element, string prefix)
        {
            MemberInfo[] members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
            WriteIndent();
            WriteString(prefix);
            bool propWritten = false;
            foreach (MemberInfo m in members)
            {
                var f = m as FieldInfo;
                var p = m as PropertyInfo;
                if (f != null || p != null)
                {
                    if (propWritten)
                    {
                        WriteTab();
                    }
                    else
                    {
                        propWritten = true;
                    }
                    WriteString(m.Name);
                    WriteString("=");
                    Type t = f != null ? f.FieldType : p.PropertyType;
                    
                    if (t.IsValueType || t == typeof(string))
                    {
                         WriteValue(GetValue(element, m, f, p)); 
                    }
                    else
                    {
                        WriteString(typeof (IEnumerable).IsAssignableFrom(t) ? "..." : "{ }");
                    }
                }
            }
            if (propWritten) WriteLine();
            WriteReflectionChildren(element, members);
        }
        protected virtual object GetValue(object element, MemberInfo m, FieldInfo f, PropertyInfo p)
        {
           return f != null ? f.GetValue(element) : p.GetValue(element, null);
        }
        

        protected void WriteReflectionChildren(object element, MemberInfo[] members)
        {
            if (_level < _depth)
            {
                foreach (MemberInfo m in members)
                {
                    var f = m as FieldInfo;
                    var p = m as PropertyInfo;
                    if (f != null || p != null)
                    {
                        Type t = f != null ? f.FieldType : p.PropertyType;
                        if (!(t.IsValueType || t == typeof(string)))
                        {
                            
                            object value =GetValue(element,m,f,p);
                            if (value != null)
                            {
                                _level++;
                                WriteObject(m.Name + ": ", value);
                                _level--;
                            }
                        }
                    }
                }
            }
        }

        protected virtual void WriteEnumerable(string prefix, IEnumerable enumerableElement)
        {
            foreach (object item in enumerableElement)
            {
                if (item is IEnumerable && !(item is string))
                {
                    WriteIndent();
                    WriteString(prefix);
                    WriteString("...");
                    WriteLine();
                    if (_level < _depth)
                    {
                        _level++;
                        WriteObject(prefix, item);
                        _level--;
                    }
                }
                else
                {
                    WriteObject(prefix, item);
                }
            }
        }
        
        protected virtual void WriteValue(object o)
        {
            if (o == null)
            {
                WriteString("null");
            }
            else if (o is DateTime)
            {
                WriteString(((DateTime)o).ToShortDateString());
            }
            else if (o is ValueType || o is string)
            {
                WriteString(o.ToString());
            }
            else if (o is IEnumerable)
            {
                WriteString("...");
            }
            else
            {
                WriteString("{ }");
            }
        }

       
    }
}

Note that this code currently throws an exception if the object passed into it is a Type, for example:

var type=typeof(string);
ObjectDumper.Write(type);


Throws: TargetInvocationException: Exception has been thrown by the target of an invocation. So... the refactoring commenced and the derived class that handles types, and also KeyValuePairs


Tuesday, January 5, 2010

My first go at Unit Testing

I've picked up "The Art of Unit Testing  with examples in .net" and I'm almost halfway done reading it. It has provided a very good walkthrough of unit testing and based on what I understand from straight reading, I've implemented some tests using Visual Studio 2008 professional's built in test functionality and RhinoMocks.

       [TestMethod]
        
public void IsValidCopyDictionary_IncludingIdentifier_EqualsReflectionCount()
        {
            
var source = Rhino.Mocks.MockRepository.GenerateStub<IAmAnAssessment>();
            
var destination=Rhino.Mocks.MockRepository.GenerateStub<IAmAnAssessment>();
            
var dictionary = ModelAssessment.ActionDictionary(destination, source, true);
            
var modelProperties=typeof (ModelAssessment).GetProperties();
            
Assert.AreEqual(dictionary.Count, modelProperties.Count(), "CopyDictionary:include is invalid");
        }
        [
TestMethod]
        
public void IsValidCopyDictionary_ExcludingIdentifier_EqualsReflectionCount()
        {
            
var source = Rhino.Mocks.MockRepository.GenerateStub<IAmAnAssessment>();
            
var destination = Rhino.Mocks.MockRepository.GenerateStub<IAmAnAssessment>();
            
var dictionary = ModelAssessment.ActionDictionary(destination, source, false);
            
var modelProperties = typeof(ModelAssessment).GetProperties();
            
Assert.AreEqual(dictionary.Count, modelProperties.Count()-1,"CopyDictionary:exclude is invalid");
        }