locked
Add-Type inheritance + LoaderExceptions RRS feed

  • Question

  • Hello,

    I'm trying to us Add-Type to build a custom type based on log4net. It seems to work fine as long as I don't do any inheritance of a log4net object. I don't understand why it would work without the inheritance but still using types from the library while it doesn't work with the inheritance.

    WORKS:

     

    [System.String]$source = @"
      using System;
      using log4net.Appender;
      
      public class TpmPowershellOracleAppender
      { 
        public log4net.Appender.AdoNetAppender GetAdoNetAppender
        {
          get
          {
            return new log4net.Appender.AdoNetAppender();
          }
        }
        
        public log4net.ILog GetLogger 
        {
          get 
          {
            log4net.ILog _log = log4net.LogManager.GetLogger(typeof(TpmPowershellOracleAppender));
            return _log;
          }
        }
      }
    "@
    
    $referencedAssemblies = ( "C:\data\PS Lib\libs\log4net.dll" )
    Add-Type -TypeDefinition $source -ReferencedAssemblies $referencedAssemblies -Language CSharp
    

    DOES NOT WORK:

     

    [System.String]$source = @"
      using System;
      using log4net.Appender;
      
      public class TpmPowershellOracleAppender : log4net.Appender.AdoNetAppender  { 
        public log4net.Appender.AdoNetAppender GetAdoNetAppender
        {
          get
          {
            return new log4net.Appender.AdoNetAppender();
          }
        }
        
        public log4net.ILog GetLogger 
        {
          get 
          {
            log4net.ILog _log = log4net.LogManager.GetLogger(typeof(TpmPowershellOracleAppender));
            return _log;
          }
        }
      }
    "@
    
    $referencedAssemblies = ( "C:\data\PS Lib\libs\log4net.dll" )
    Add-Type -TypeDefinition $source -ReferencedAssemblies $referencedAssemblies -Language CSharp
    


    The problem is that I get an "Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information." error.

    In Powershell, how would I get access to the LoaderExceptions property?



    • Edited by Yves Dhondt Saturday, January 21, 2012 4:56 PM
    Saturday, January 21, 2012 4:53 PM

Answers

  • PS >  gc F:\flat.cs
    namespace FlatShapes
    {
            public class Circle
            {
                    private double _radius;
    
                    public double Radius
                    {
                            get { return (_radius < 0) ? 0.00 : _radius; }
                            set     { _radius = value; }
                    }
                    public double Diameter
                    {
                            get     { return Radius * 2; }
                    }
                    public double Circumference
                    {
                            get     { return Diameter * 3.14159; }
                    }
                    public double Area
                    {
                            get     { return Radius * Radius * 3.14159; }
                    }
            }
    }
    
    PS >  C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /target:library flat.cs
    Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927
    for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
    Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
    
    $code = @'
    using FlatShapes;
    namespace Volumes
    {
    	public class Sphere : FlatShapes.Circle
    	{
    		new public double  Area
    		{
    			get	{ return 4 * Radius * Radius * 3.14159; }
    		}
    	
    		public double Volume
    		{
    			get	{ return 4 * 3.14159 * Radius * Radius * Radius / 3; }
    		}
    	}
    }
    '@
    
    
    PS >  Add-Type -TypeDefinition $code  -ReferencedAssemblies "F:\flat.dll"
    Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more informati
    on.
    At line:1 char:9
    
    
    PS >  $referencedAssemblies = "F:\flat.dll"
    PS >  Add-Type -Path $referencedAssemblies
    PS >  $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    PS > $cpar.ReferencedAssemblies.Add($referencedAssemblies)
    0
    PS >  Add-Type -TypeDefinition $code  -CompilerParameters $cpar
    PS >  New-Object Volumes.Sphere
    
    
    Area          : 0
    Volume        : 0
    Radius        : 0
    Diameter      : 0
    Circumference : 0
    
    
    Try this for your code:
    
    $referencedAssemblies = "C:\data\PS Lib\libs\log4net.dll"
    Add-Type -Path $referencedAssemblies
    $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    $cpar.ReferencedAssemblies.Add($referencedAssemblies)
    Add-Type -TypeDefinition $code  -CompilerParameters $cpar
    
    
    
    
    
    
    

    I'm using this example - http://www.functionx.com/csharp1/examples/inheritance.htm

     

    • Marked as answer by Yves Dhondt Sunday, January 22, 2012 4:29 PM
    Sunday, January 22, 2012 3:02 PM

All replies

  • Try this:
    $referencedAssemblies = ( "C:\data\PS Lib\libs\log4net.dll" )
    $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    $cpar.ReferencedAssemblies.Add($referencedAssemblies)
    Add-Type -TypeDefinition $source  -CompilerParameters $cpar
    
    
     
    Sunday, January 22, 2012 10:56 AM
  • Thanks for the suggestion but it doesn't work.

    The problem doesn't seem to be with the referenced assemblies. The code without the inheritance uses the exact same libraries from the inheritance sample without flaw. The problem seems to be the inheritance. Either the compiler goes deeper with the loading of types or something else is going on.

    I managed to get the exact exception out of the LoaderExceptions property by wrapping everything inside a try/catch

    try
    {
      ...
    }
    catch [System.Reflection.ReflectionTypeLoadException]
    {
      Write-Host "Message: $($_.Exception.Message)"
      Write-Host "StackTrace: $($_.Exception.StackTrace)"
      Write-Host "LoaderExceptions: $($_.Exception.LoaderExceptions)"
    }
    

    The message I got back has me stumped:

    LoaderExceptions: System.IO.FileNotFoundException: Could not load file or assembly 'log4net, Version=1.2.11.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a' or one of its dependencies. The system cannot find the file specified.
    File name: 'log4net, Version=1.2.11.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'
    
    WRN: Assembly binding logging is turned OFF.
    To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
    Note: There is some performance penalty associated with assembly bind failure logging.
    To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].

    I probably misread this error, but to me it sounds like a circular reference thing. As the assembly is added as a referenced assembly it should find it. And it really does. If you take the 'works' sample from my first post and leave out the referenced assembly, the compiler will bark on the fact that log4net is missing (which is correct). So it really is there. But once you start inheriting, it cannot find it.

    Sunday, January 22, 2012 2:29 PM
  • PS >  gc F:\flat.cs
    namespace FlatShapes
    {
            public class Circle
            {
                    private double _radius;
    
                    public double Radius
                    {
                            get { return (_radius < 0) ? 0.00 : _radius; }
                            set     { _radius = value; }
                    }
                    public double Diameter
                    {
                            get     { return Radius * 2; }
                    }
                    public double Circumference
                    {
                            get     { return Diameter * 3.14159; }
                    }
                    public double Area
                    {
                            get     { return Radius * Radius * 3.14159; }
                    }
            }
    }
    
    PS >  C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe /target:library flat.cs
    Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.4927
    for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727
    Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.
    
    $code = @'
    using FlatShapes;
    namespace Volumes
    {
    	public class Sphere : FlatShapes.Circle
    	{
    		new public double  Area
    		{
    			get	{ return 4 * Radius * Radius * 3.14159; }
    		}
    	
    		public double Volume
    		{
    			get	{ return 4 * 3.14159 * Radius * Radius * Radius / 3; }
    		}
    	}
    }
    '@
    
    
    PS >  Add-Type -TypeDefinition $code  -ReferencedAssemblies "F:\flat.dll"
    Add-Type : Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more informati
    on.
    At line:1 char:9
    
    
    PS >  $referencedAssemblies = "F:\flat.dll"
    PS >  Add-Type -Path $referencedAssemblies
    PS >  $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    PS > $cpar.ReferencedAssemblies.Add($referencedAssemblies)
    0
    PS >  Add-Type -TypeDefinition $code  -CompilerParameters $cpar
    PS >  New-Object Volumes.Sphere
    
    
    Area          : 0
    Volume        : 0
    Radius        : 0
    Diameter      : 0
    Circumference : 0
    
    
    Try this for your code:
    
    $referencedAssemblies = "C:\data\PS Lib\libs\log4net.dll"
    Add-Type -Path $referencedAssemblies
    $cpar = New-Object System.CodeDom.Compiler.CompilerParameters
    $cpar.ReferencedAssemblies.Add($referencedAssemblies)
    Add-Type -TypeDefinition $code  -CompilerParameters $cpar
    
    
    
    
    
    
    

    I'm using this example - http://www.functionx.com/csharp1/examples/inheritance.htm

     

    • Marked as answer by Yves Dhondt Sunday, January 22, 2012 4:29 PM
    Sunday, January 22, 2012 3:02 PM
  • This works perfectly.

    It seem like the referenced assemblies need to be loaded as well before you are able to use them. That was what was missing from my code and your original reply. I don't really understand why though.

    Sunday, January 22, 2012 4:33 PM