I have a C# class that has a property(name is List) of type Microsoft.VisualBasic.Collection. We need to exposed this property to COM. For that, I was writing an interface for my class such that the property would marshaled as of UnmanagedType.IDispatch.
Something like this:
[DispId(0x68030000)]
Collection List { [DispId(0x68030000)] [return: MarshalAs(UnmanagedType.IDispatch)] get; }
This piece of code was earlier in VB and was being used by C++ as tye VT_DISPATCH. However, while building the C# library, I get the following error:
C:\Program Files
(x86)\MSBuild\14.0\bin\Microsoft.Common.CurrentVersion.targets(4335,5):
error MSB3212: The assembly "Name.dll" could not be converted to a
type library. Type library exporter encountered an error while
processing 'Namespace.InterfaceName.get_List(#0), ProjectName'. Error:
Error loading type library/DLL.
I read through few of the posts online which suggested that such errors might cause because of repetitive GUIDs. But that is not the case. I tried with multiple GUIDs. I don't feel this is an issue with any other attribute that I had set on my Interface since, I am able to marshal other properties and function calls ( some of them use primitive types and others use custom classes) successfully.
This is how it is consumed in the consuming C++ application:
LPDISPATCH result;
InvokeHelper(0x68030000, DISPATCH_PROPERTYGET, VT_DISPATCH, (void*)&result, NULL);
return result;
This has become a go live issue with the client and I really do not have much time to continue investigation since this is due tomorrow.
Appreciate any help!
I don't think Microsoft.VisualBasic.Collection is COM-visible. Therefore, you cannot use this type as a return value or parameter in a COM class or interface. However, ICollection (which Microsoft.VisualBasic.Collection implements) is COM visible. If that would suit your purposes, use that as the type of your property rather than Microsoft.VisualBasic.Collection.
Related
I have a huge code base and I recently made a change where I changed the type of a parameter from String to a custom class. On the next compile I got all the areas where the impact was, but areas where the input type was of type Object failed. for e.g.
String str = "32"
int i = Convert.ToInt32(str)
Now I have changed String to a new custom type lets say MyCustomClass I would now want following code to fail on next compile
MyCustomClass str = new MyCustomClass("32")
int i = Convert.ToInt32(str)
but it won't as Convert.ToInt32 also accepts type Object. Is there some way I can make a change in MyCustomClass that it's not considered Object anymore.
Please note: Convert.ToInt32 is only used for sample I have many more such functions, so please focus your suggestion/answer to question asked.
Override ToString() and IConvertible
You said in the comments that your intentions are to find places where your object, which had previously been treated as a string, and are now being treated as an object.
In these situations typically, the third-party code would call .ToString() on your object to get something which it can use.
So, Convert.ToInt32(str) is equivalent to Convert.ToInt32(str.ToString()).
If you implement ToString() and IConvertible to return whatever your old version of str looked like then it should continue to work in the same way as the old version.
Probably.
Sorry I know that is not the 100% perfect compile time answer you were looking for, but I think you also know very well that your MyCustomClass will always be considered object.
Possible compile time answer:
Write a tool which uses reflection to iterate over every class/struct/interface in every system/third-party DLL.
Output a load of CS files which contain all these same classes, but just throw NotImplementedException.
(T4 could help you do this)
Compile these classes into dummy.dll
Your .csproj now references only this one dummy.dll, instead of the real dlls.
Your project should compile fine against the dummy dll.
Look at your dummy.cs files and delete any use of object.
Re-compile... and suddenly you get a load of compile time errors showing you anywhere you are using an object.
Impliment an implicit cast from MyCustomClass to String.
public static implicit operator string(MyCustomClass str)
{
return "Legacy respresentation of str";
}
This allows the complier the choice of choosing ToInt32(Object) or ToInt32(String), and I bet it favours the later.
This way all your existing function calls will remain the same so you wont have to be concerned about third party implentation details.
(Sorry, I am not at a computer right now so I can`t test that my assumtion is correct. If you do test this, be sure to consider extension methods, as they can affect the conpilers desision making in unexpected ways)
When composing or using ExportProvider.GetExportedValues Method. Exception CompositionContractMismatchException is thrown. I'm converting legacy code that was sprinked with static factories, so I simply want to expose there return values to MEF container, for example.
namespace fooProject
{
static class SomeExportFactory
{
[Export(typeof(IFoo))]
public static FooImp Generate()
{
return new FooImp();
}
}
}
So, this simple illustration would throw an exception with this message "Cannot cast the underlying exported value of type 'fooProject.SomeExportFactory.Generate (ContractName="IFoo")' to type 'IFoo'." to type "IFoo".].
Any guesses to what could be causing this? I already scoured the internet and CompositionContractMismatchException when trying to use MEF with MVC controller is the closes thing I can find, but I do not have duplicate assemblies like in that case.
Ok, I found the answer. Don't export from static functions!!!. Hope this helps someone else in this situation.
MEF throws a cryptic exception if you are trying to exporting from a static function. The exception looks like a potentially duplicate assemblies loaded. Like some answers have suggested, but alas.
For people that are interested in more details read on (links to current MEF implementations are provided).
The code brakes down at ContractServices.cs. You will find a public static function "TryCast" there. It provides a mechanism for MEF to provide instance of the object boxed to a specified type. But it only checks for 2 conditions. First, the object passed in, is already of desired type. Second, object is provided through ExportedDelegate (probably how member function Export works). If your export does not fit any of these then false is returned and immediately CompositionContractMismatchException is thrown (see ExportServices.cs T CastExportedValue(ICompositionElement element, object exportedValue) function).
I wish they would have throw DummyDontUseStaticException in this situation :p
I have discovered the cause of the issue. An answer has been posted below.
EDIT: The problem has changed, please see "The problem" section.
I am using LuaInterface. The generic call for lua functions using this library has this signature LuaFunction.Call(params object[] args). I have created a wrapper function that catches exceptions from the library and formats them for display on the in-game console window.
I am trying to call a lua function, but it is not receiving the arguments. This is the line in C#
Game.Instance.scriptEngine.Call("GenerateChunk", chunks[chunkID], GetChunkGridPosition(chunkID));
Which is simply wrapping a call to this Lua function that accepts two arguments:
//lua
function GenerateChunk(worldChunk, chunkGridPosition)
Log(LogLevel.Error, worldChunk.ToString());
Log(LogLevel.Error, chunkGridPosition.ToString());
end
that merely calls back into a C# Log function (which resolves correctly, and is visible in the Lua context).
The problem is that I am getting an "invalid arguments to method call" error from luainterface when attempting to call the GenerateChunk function, throwing this back:
invalid arguments to method call
at JASG.ScriptEngine.LuaError(Exception ex) Scripting\ScriptEngine.cs:line 144
at JASG.ScriptEngine.Call(String fnName, Object[] args) Scripting\ScriptEngine.cs:line 86
at JASG.ChunkManager.WakeChunk(Int32 chunkID) World\ChunkManager.cs:line 123
at JASG.ChunkManager.GetChunk(Int32 chunkID, Boolean wakeIfAsleep) World\ChunkManager.cs:line 53
I have tried various ways of calling the ScriptEngine.Call method, tried wrapping the arguments in an object[] array, etc., but no dice. Any ideas why lua is not receiving my arguments that I am passing? I have verified both arguments are non-null in C# when being passed in.
I've never used Lua before, but I've seen this kind of strange behaviors with calling COM objects (or any interop), or when the target assembly call is loaded on a different App Domain, or any other technology that intercommunicates a .Net assembly with a non-.Net one.
Have you tried using the [Serializable] attribute on the classes that define the result of "chunks[chunkID]" and "GetChunkGridPosition(chunkID)"? Are all your interop classes and types compatible between both assemblies?
Just thinking out loud here.
Side note: you should reduce your code to the shortest example that produces the problem. For instance, we don't need to see your wrapper function. You should have tried removing it. If that solved the problem, it's an important clue you should have been mentioned. If the problem remained, then that code is just a distracting irrelevancy for anyone reading this.
Your problem could be in your Log function. Everything thing else looks fine, that's the only code we can't actually see, and your problem can be reproduced like this:
public static void Log(int errorLevel, string message)
{
Console.WriteLine(message);
}
public void Test()
{
var lua = new Lua();
lua.RegisterFunction("Log", this, GetType().GetMethod("Log"));
lua.DoString("function foo() Log('a','b') end");
lua.GetFunction("foo").Call();
}
In this case, because 'a' cannot be marshaled into a number.
I incorrectly identified the problem as being with the call into Lua. The error message I was receiving was in fact originating from the Lua script calling back into my C# Log function.
I have discovered the hard way that in spite of exposing the enum LogManager.LogLevel to the lua script envronment, Lua does not support enum types. Thus,
Log(LogLevel.Debug, "hello");
was becoming
Log("Debug", "hello");
when marshalled by LuaInterface for the C# function. It was not until I created an ancillary ScriptLog(string level, string msg) that I was able to properly use the function from within lua. I wanted to keep the functionality of being able to use the enum names within Lua.
NOTE: As Lua does not support enum types, tonumber(LogLevel.Debug) fails as well.
I got curious as to where Type.GetType() is implemented, so I took a peek at the assembly and noticed Type.GetType() calls base.GetType() and since Type inherits from MemberInfo I took a look and it is defined as _MemberInfo.GetType() which returns this.GetType(). Since I cannot find the actual code that shows how C# can get type information I would like to know:
How does the CLR get Type and MemberInfo from objects at Runtime?
The ACTUAL source for .NET Framework 2.0 is available on the internet (for educational purposes) here: http://www.microsoft.com/en-us/download/details.aspx?id=4917
This is the C# Language implementation. You can use 7zip to unpack it. You will find the reflection namespace here (relatively):
.\sscli20\clr\src\bcl\system\reflection
I am digging for the specific implementation you are asking about, but this is a good start.
UPDATE: Sorry, but I think its a dead end. Type.GetType() calls to the base implementation which comes from System.Object. If you inspect that codefile (.\sscli20\clr\src\bcl\system\object.cs) you will find the method is extern (see code below). Further inspect could uncover the implementation, but its not in the BCL. I suspect it will be in C++ code somewhere.
// Returns a Type object which represent this object instance.
//
[MethodImplAttribute(MethodImplOptions.InternalCall)]
public extern Type GetType();
UPDATE (AGAIN): I dug deeper and found the answer in the implementation of the CLR virtual machine itself. (Its in C++).
The first piece of puzzle is here:
\sscli20\clr\src\vm\ecall.cpp
Here we see the code that maps the external call to an C++ function.
FCFuncStart(gObjectFuncs)
FCIntrinsic("GetType", ObjectNative::GetClass, CORINFO_INTRINSIC_Object_GetType)
FCFuncElement("InternalGetHashCode", ObjectNative::GetHashCode)
FCFuncElement("InternalEquals", ObjectNative::Equals)
FCFuncElement("MemberwiseClone", ObjectNative::Clone)
FCFuncEnd()
Now, we need to go find ObjectNative::GetClass ... which is here:
\sscli20\clr\src\vm\comobject.cpp
and here is the implementation of GetType:
FCIMPL1(Object*, ObjectNative::GetClass, Object* pThis)
{
CONTRACTL
{
THROWS;
SO_TOLERANT;
DISABLED(GC_TRIGGERS); // FCallCheck calls ForbidenGC now
INJECT_FAULT(FCThrow(kOutOfMemoryException););
SO_TOLERANT;
MODE_COOPERATIVE;
}
CONTRACTL_END;
OBJECTREF objRef = ObjectToOBJECTREF(pThis);
OBJECTREF refType = NULL;
TypeHandle typeHandle = TypeHandle();
if (objRef == NULL)
FCThrow(kNullReferenceException);
typeHandle = objRef->GetTypeHandle();
if (typeHandle.IsUnsharedMT())
refType = typeHandle.AsMethodTable()->GetManagedClassObjectIfExists();
else
refType = typeHandle.GetManagedClassObjectIfExists();
if (refType != NULL)
return OBJECTREFToObject(refType);
HELPER_METHOD_FRAME_BEGIN_RET_ATTRIB_2(Frame::FRAME_ATTR_RETURNOBJ, objRef, refType);
if (!objRef->IsThunking())
refType = typeHandle.GetManagedClassObject();
else
refType = CRemotingServices::GetClass(objRef);
HELPER_METHOD_FRAME_END();
return OBJECTREFToObject(refType);
}
FCIMPLEND
One last thing, the implementation of GetTypeHandle along with some other supporting functions can be found in here:
\sscli20\clr\src\vm\object.cpp
The most significant parts of reflection are implemented as part of the CLI itself. As such, you could look at either the MS CLI reference source (aka "Rotor"), or the mono source. But: it will mostly be C/C++. The public API implementation details (MethodInfo, Type etc) may be C#.
It might not answer you question directly. However, here is a little outline of how managed code knows everything about types.
Whenever you compile code the compiler analyzes/parses the source files and collects information it encounters. For example take a look at class below.
class A
{
public int Prop1 {get; private set;}
protected bool Met2(float input) {return true;}
}
The compiler can see that this is an internal class with two members. Member one is a property of type int with private setter. Member 2 is a protected method with name Met2 and type boolean that takes float input (input name is 'input'). So, it has all this information.
It stores this information in the assembly. There are a couple of tables. For example classes (types) all leave in one table, methods live in another table. Think in turms of SQL tables, though they are definitely are not.
When a user (developer) wants to know information about a type it calls GetType method. This method relies on objects hidden field - type object pointer. This object is basically a pointer to a class table. Each class table will have a pointer to the first method in methods table. Each method record will have a pointer to the first parameter in the parameters table.
PS: this mechamism is key to making .NET assemblies more secure. You cannot replace pointers to methods. It will break the signature of the assebmly.
JIT compilation relies heavily on this tables as well
As #GlennFerrieLive points out, the call to GetType is an InternalCall which means the implementation is within the CLR itself and not in any of the BCL.
My understanding is that the internal CLR method takes the runtime type information from the this pointer, which basically amounts to the name of the type. It then look up the complete type information from the metadata present in all loaded assemblies (presumably, in the current appdomain), which is what makes reflection rather expensive. The metadata area is basically a database of all the types and members present in the assembly and it constructs an instance of Type or Method|Property|FieldInfo from this data.
Please, help me to explain the following behavior:
dynamic d = 1;
ISet<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The code compiles with no errors/warnings, but at the last line I get the following exception:
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.Generic.ISet<object>' does not contain a definition for 'Contains'
at CallSite.Target(Closure , CallSite , ISet`1 , Object )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2[T0,T1](CallSite site, T0 arg0, T1 arg1)
at FormulaToSimulation.Program.Main(String[] args) in
As far as I can tell, this is related to dynamic overload resolution, but the strange things are
(1) If the type of s is HashSet<dynamic>, no exception occurs.
(2) If I use a non-generic interface with a method accepting a dynamic argument, no exception occurs.
Thus, it looks like this problem is related particularly with generic interfaces, but I could not find out what exactly causes the problem.
Is it a bug in the compiler/typesystem, or legitimate behavior?
The answers you have received so far do not explain the behaviour you are seeing. The DLR should find the method ICollection<object>.Contains(object) and call it with the boxed integer as a parameter, even if the static type of the variable is ISet<dynamic> instead of ICollection<dynamic> (because the former derives from the latter).
Therefore, I believe this is a bug and I have reported it to Microsoft Connect. If it turns out that the behaviour is somehow desirable, they will post a comment to that effect there.
Why it compiles: the entire expression is evaluated as dynamic (hover your mouse over it inside your IDE to confirm), which means that it is a runtime check.
Why it bombs: My (completely wrong, see below) guess is that it is because you cannot implement a dynamic interface in such a manner. For example, the compiler does not allow you to create a class that implements ISet<dynamic>, IEnumerable<dynamic>, IList<dynamic>, etc. You get a compile-time error stating "cannot implement a dynamic interface". See Chris Burrows' blog post on this subject.
http://blogs.msdn.com/b/cburrows/archive/2009/02/04/c-dynamic-part-vii.aspx
However, since it's hitting the DLR anyway, you can make s completely dynamic.
dynamic s = new HashSet<dynamic>;
s.Contains(d);
Compiles and runs.
Edit: the second part of this answer is completely wrong. Well, it is correct in that you can't implement such an interface as ISet<dynamic>, but that's not why this blows up.
See Julian's answer below. You can get the following code to compile and run:
ICollection<dynamic> s = new HashSet<dynamic>();
s.Contains(d);
The Contains method is defined on ICollection<T>, not ISet<T>. The CLR doesn't allow an interface base method to be called from a derived interface. You usually doesn't see this with static resolution because the C# compiler is smart enough to emit a call to ICollection<T>.Contains, not the non-existing ISet<T>.Contains.
Edit: The DLR mimics the CLR behavior, that's why you get the exception. Your dynamic call is done on an ISet<T>, not an HashSet<T> the DLR will mimics the CLR: for an interface, only interfaces methods are searched for, not base interfaces (contrary to classes where this behavior is present).
For an in-depth explanation, see a previous response of mine to a similar question:
Strange behaviour when using dynamic types as method parameters
Note that the type dynamic doesn’t actually exist at run-time. Variables of that type are actually compiled into variables of type object, but the compiler turns all the method calls (and properties and everything) that involve such an object (either as the this object or as a parameter) into a call that is resolved dynamically at runtime (using System.Runtime.CompilerServices.CallSiteBinder and related magic).
So what happens in your case is that the compiler:
turns ISet<dynamic> into ISet<object>;
turns HashSet<dynamic> into HashSet<object>, which becomes the actual run-time type of the instance you’re storing in s.
Now if you try to invoke, say,
s.Contains(1);
this actually succeeds without a dynamic invocation: it really just calls ISet<object>.Contains(object) on the boxed integer 1.
But if you try to invoke
s.Contains(d);
where d is dynamic, then the compiler turns the statement into one that determines, at runtime, the correct overload of Contains to call based on the runtime type of d. Perhaps now you can see the problem:
The compiler emits code that definitely searches the type ISet<object>.
That code determines that the dynamic variable has type int at runtime and tries to find a method Contains(int).
ISet<object> does not contain a method Contains(int), hence the exception.
ISet interface does not have a method 'Contains', HashSet does however?
EDIT
What i meant to say was the binder resolves 'Contains' when given the HashSet concreate type, but doesnt find the inherited 'Contains' method in the interface...