-
Notifications
You must be signed in to change notification settings - Fork 370
Description
Greetings;
I'm not sure if there is an issue with my .CSX Script file, or if there is an issue with ScriptCS or with the underlying implementation of Roslyn, but when I attempt to execute a script that contains a generic C# method, I receive the runtime error "ERROR: Unable to change after type has been created".
My .CSX Script File that contains the generic method, string GetHashKeyForFile(string filePath) where T : HashAlgorithm, new(), is implemented as shown in the listing below:
[Contents of GenericHashKeys.csx ScriptCS File]
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
const string sampleJPEGFile = @"C:\Misc\Images\HomerDoh.jpg";
const string hashKeyFormat = @"{0} Hash Key For File: {1}: {2}";
string GetHashKeyForFile<T>(string filePath) where T : HashAlgorithm, new()
{
string hashKey = string.Empty;
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return string.Empty;
}
using (FileStream fileStream = File.OpenRead(filePath))
{
if (fileStream != null)
{
using (BufferedStream bufferedFileStream = new BufferedStream(fileStream))
{
if (bufferedFileStream != null)
{
using (T cryptoProvider = new T())
{
cryptoProvider.ComputeHash(bufferedFileStream);
hashKey = ByteArrayToString(cryptoProvider.Hash);
}
}
}
}
}
return hashKey;
}
string ByteArrayToString(byte[] byteArray)
{
if (byteArray == null || byteArray.Length == 0)
{
return string.Empty;
}
StringBuilder hexBuffer = new StringBuilder(byteArray.Length * 2);
if (hexBuffer != null)
{
foreach (byte value in byteArray)
{
hexBuffer.AppendFormat("{0:X2}", value);
}
return hexBuffer.ToString();
}
return string.Empty;
}
string md5HashKey = GetHashKeyForFile<MD5CryptoServiceProvider>(sampleJPEGFile);
string trace =
string.Format(hashKeyFormat, "MD5", sampleJPEGFile, md5HashKey);
Console.Out.WriteLine(trace);
string sha1HashKey = GetHashKeyForFile<SHA1CryptoServiceProvider>(sampleJPEGFile);
trace =
string.Format(hashKeyFormat, "SHA1", sampleJPEGFile, sha1HashKey);
Console.Out.WriteLine(trace);When I execute the above script using the ScriptCS Version 0.9.0 updates, I receive the following runtime error:
J:\ScriptCS->scriptcs GenericHashKeys.csx
ERROR: Unable to change after type has been created.
J:\ScriptCS->
When I execute the same script with the logging level to debug, I get the following trace:
J:\ScriptCS->scriptcs GenericHashKeys.csx -log debug
DEBUG: Resolving ModuleLoader
DEBUG: Registering initialization services
DEBUG: Registering default: ScriptCs.Contracts.IFileSystem
DEBUG: Registering default: ScriptCs.Contracts.IAssemblyUtility
DEBUG: Registering default: ScriptCs.Contracts.IPackageContainer
DEBUG: Registering default: ScriptCs.Contracts.IPackageAssemblyResolver
DEBUG: Registering default: ScriptCs.Contracts.IAssemblyResolver
DEBUG: Registering default: ScriptCs.IModuleLoader
DEBUG: Resolving FileSystem
DEBUG: Loading modules from: C:\Users\ClockEndGooner\AppData\Local\scriptcs
DEBUG: Initializing modules
DEBUG: Modules initialized
DEBUG: Resolving ScriptServices
DEBUG: Registering runtime services
DEBUG: Registering default: ScriptCs.Contracts.IFileSystem
DEBUG: Registering default: ScriptCs.Contracts.IAssemblyUtility
DEBUG: Registering default: ScriptCs.Contracts.IPackageContainer
DEBUG: Registering default: ScriptCs.Contracts.IPackageAssemblyResolver
DEBUG: Registering default: ScriptCs.Contracts.IAssemblyResolver
DEBUG: Registering default: ScriptCs.Contracts.IScriptHostFactory
DEBUG: Registering default: ScriptCs.Contracts.IFilePreProcessor
DEBUG: Registering default: ScriptCs.Contracts.IScriptPackResolver
DEBUG: Registering default: ScriptCs.Contracts.IInstallationProvider
DEBUG: Registering default: ScriptCs.Contracts.IPackageInstaller
DEBUG: Registering default: ScriptCs.ScriptServices
DEBUG: Registering default: ScriptCs.Contracts.IObjectSerializer
DEBUG: Registering default: ScriptCs.Contracts.IConsole
DEBUG: Resolving AssemblyResolver
DEBUG: Initializing script packs
DEBUG: Starting pre-processing
DEBUG: Processing GenericHashKeys.csx...
DEBUG: Pre-processing finished successfully
DEBUG: Starting execution in engine
DEBUG: Starting to create execution components
DEBUG: Creating script host
DEBUG: Creating session
DEBUG: Adding reference to System
DEBUG: Adding reference to System.Core
DEBUG: Adding reference to System.Data
DEBUG: Adding reference to System.Data.DataSetExtensions
DEBUG: Adding reference to System.Xml
DEBUG: Adding reference to System.Xml.Linq
DEBUG: Importing namespace System
DEBUG: Importing namespace System.Collections.Generic
DEBUG: Importing namespace System.Linq
DEBUG: Importing namespace System.Text
DEBUG: Importing namespace System.Threading.Tasks
DEBUG: Importing namespace System.IO
DEBUG: Importing namespace System.Diagnostics
DEBUG: Importing namespace System.Security.Cryptography
DEBUG: Starting execution
DEBUG: Finished execution
DEBUG: Terminating packs
ERROR: Unable to change after type has been created.
DEBUG: System.InvalidOperationException: Unable to change after type has been created.
at System.Reflection.Emit.TypeBuilder.SetParent(Type parent)
at Roslyn.Compilers.CodeGen.ReflectionEmitter.DefineGenericParameterConstraints(GenericTypeParameterBuilder gpBuilder, IGenericParameter typeParameter)
at Roslyn.Compilers.CodeGen.ReflectionEmitter.Emit(CancellationToken cancellationToken, IMethodReference entryPoint)
at Roslyn.Compilers.CSharp.Compilation.Emit(ModuleBuilder moduleBuilder, IAssemblyLoader assemblyLoader, Func`2 assemblySymbolMapper, CancellationToken cance
llationToken, Boolean recoverOnError, ReadOnlyArray`1& compiledAssemblyImage)
at Roslyn.Compilers.CSharp.Compilation.CommonEmit(ModuleBuilder moduleBuilder, IAssemblyLoader assemblyLoader, Func`2 assemblySymbolMapper, CancellationToken
cancellationToken, Boolean recoverOnError, ReadOnlyArray`1& compiledAssemblyImage)
at Roslyn.Scripting.CommonScriptEngine.TryEmitSubmission(CommonCompilation compilation, DiagnosticBag diagnostics, Type delegateType, Boolean collectible, Ca
ncellationToken cancellationToken, Delegate& factory)
at Roslyn.Scripting.CommonScriptEngine.Compile(String code, String path, DiagnosticBag diagnostics, Session session, Type delegateType, Type returnType, Canc
ellationToken cancellationToken, Boolean isInteractive, Boolean isExecute, CommonCompilation& compilation, Delegate& factory)
at Roslyn.Scripting.CommonScriptEngine.CompileSubmission[T](String code, Session session, String path, Boolean isInteractive)
at ScriptCs.Engine.Roslyn.RoslynScriptEngine.Execute(String code, Session session)
J:\ScriptCS->
In comparison, I've been able to verify that syntactically and functionally, the methods in my script file are correct by trying a quick and simple version as a Windows Console application under Visual Studio 2010 targeting the .NET 4.0 Framework.
[GenericHashKey.Program.cs]
using System;
using System.Diagnostics;
using System.IO;
using System.Security.Cryptography;
using System.Text;
namespace GenericHashKey
{
class Program
{
private static readonly string sampleJPEGFile = @"C:\Misc\Images\HomerDoh.jpg";
private static readonly string hashKeyFormat = @"{0} Hash Key For File: {1}: {2}";
private static string GetHashKeyForFile<T>(string filePath) where T : HashAlgorithm, new()
{
string hashKey = string.Empty;
if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
{
return string.Empty;
}
using (FileStream fileStream = File.OpenRead(filePath))
{
if (fileStream != null)
{
using (BufferedStream bufferedFileStream = new BufferedStream(fileStream))
{
if (bufferedFileStream != null)
{
using (T cryptoProvider = new T())
{
cryptoProvider.ComputeHash(bufferedFileStream);
hashKey = ByteArrayToString(cryptoProvider.Hash);
}
}
}
}
}
return hashKey;
}
private static string ByteArrayToString(byte[] byteArray)
{
if (byteArray == null || byteArray.Length == 0)
{
return string.Empty;
}
StringBuilder hexBuffer = new StringBuilder(byteArray.Length * 2);
if (hexBuffer != null)
{
foreach (byte value in byteArray)
{
hexBuffer.AppendFormat("{0:X2}", value);
}
return hexBuffer.ToString();
}
return string.Empty;
}
static void Main(string[] args)
{
string md5HashKey = GetHashKeyForFile<MD5CryptoServiceProvider>(sampleJPEGFile);
string trace =
string.Format(hashKeyFormat, "MD5", sampleJPEGFile, md5HashKey);
Console.Out.WriteLine(trace);
string sha1HashKey = GetHashKeyForFile<SHA1CryptoServiceProvider>(sampleJPEGFile);
trace =
string.Format(hashKeyFormat, "SHA1", sampleJPEGFile, sha1HashKey);
Console.Out.WriteLine(trace);
return;
}
}
}Executing the above program from the command line results in the following output, and both the MD5 and SHA-1 hash keys emitted match the values listed in the "File Hashes" tab inside the Properties dialog box in Windows Explorer:
C:\work\NET\GenericHashKey\GenericHashKey\bin\Debug->GenericHashKey
MD5 Hash Key For File: C:\Misc\Images\HomerDoh.jpg: 408F57625000D2C2BCFC5D6F73BFD650
SHA1 Hash Key For File: C:\Misc\Images\HomerDoh.jpg: FB4B99DCD949DC3C9E119A7A31E78B9B76FB222C
C:\work\NET\GenericHashKey\GenericHashKey\bin\Debug->
Any help or guidance you could provide on how to correct this, especially if there's an issue with my code, would be greatly appreciated.
Thank you in advance for your time, help and patience.