IdentityHashCode on the CompactFramework?

C

Carl Rosenberger

Hi all,

our C# object database engine is using the
System.Object.GetHashCode() method to manage
references to instantiated objects.

Our port to the CompactFramework is just about
completed except for one remaining problem:
If user classes override the GetHashCode() method,
our reference system will fail.

On the 1.0 .NET framework it was possible to use
reflection to achieve the desired result:
(typeof(System.Object)).GetMethod("GetHashCode").Invoke(obj, null);

We observe that the behaviour of reflection has changed
with .NET 1.1 and virtual methods (the overriden ones)
are called. The same appears to happen on the CompactFramework.
Are there any other MS platforms with different behaviour that
we need to be aware of?

On the regular 1.1 framework we can use:
System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode(ob);
This method is not available on the CompactFramework.

What other options do we have?
Is there an alternative method anywhere?

Can we maybe include some IL code with our build to call
System.Object.GetHashCode() ?
How would we do this?

Thanks in advance for any hints.

Kind regards,
Carl
 
A

Alex Feinman [MVP]

I'm slightly confused as of what are you trying to achieve here.
You are saying that your reference system will fail if the GetHashCode is
overrriden. Supposedly you are comparing the result of GetHashCode to
something you have previously stored. But how did you obtain the original
reference to which you are comparing the hash code in the first place???

Anyway, if you need to get system hash code for the object, you can do it
like this (warning! undocumented and may change in the future builds):

Type t = typeof(object).Assembly.GetType("System.PInvoke.EE");

int hashCode = (int)t.GetMethod("Object_GetHashCode",
BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static).Invoke(null,
new object[] { obj } );

HTH

Alex Feinman
 
C

Carl Rosenberger

Alex said:
I'm slightly confused as of what are you trying to achieve here.
You are saying that your reference system will fail if the GetHashCode is
overrriden. Supposedly you are comparing the result of GetHashCode to
something you have previously stored.

Exactly!

We are using the result of Object#GetHashCode() to store and to
find WeakReferences to all instatiated objects in our reference
B-Tree. This is necessary to recognize continues calls to our
"store" method as updates and to provide a fast implementation.

The result of GetHashCode() is not allowed to change, otherwise
the reference system will fail. The GetHashCode() value that
System.Object returns works very good for our usecase, since it's
unique.

But how did you obtain the original
reference to which you are comparing the hash code in the first place???

The original reference is created when the object is retrieved
from our database engine or when it is stored to it.

The value itself is not terribly important for us, as long as it
stays the same during the lifetime of the object. Of course our
system will work faster, if duplicate GetHashCode() return values
are rare.

Anyway, if you need to get system hash code for the object, you can do it
like this (warning! undocumented and may change in the future builds):

Type t = typeof(object).Assembly.GetType("System.PInvoke.EE");

int hashCode = (int)t.GetMethod("Object_GetHashCode",
BindingFlags.Public|BindingFlags.NonPublic|BindingFlags.Static).Invoke(null,
new object[] { obj } );

HTH

Thanks, although the reflection method call looks wild, it seems
to get the job done perfectly.

The workaround only works in the CompactFramework environment.
If I run the created .exe in the normal 1.1 Framework, a
System.PInvoke.EE class will not be found.

That's perfectly O.K. for us. Let's hope the CompactFramework
development team comes up with a suitable public replacement,
if the internal method call changes.

Thanks again for the fast and good help!

Kind regards,
Carl
 
C

Carl Rosenberger

Carl said:
Thanks, although the reflection method call looks wild, it seems
to get the job done perfectly.

Hi again,

I quickly put together a generic class that is intended to
work on all of our targetted platforms:
- .NET framework 1.1
- .NET framework 1.0
- CompactFramework

In case anyone else wants to use it, below I send along the
sourcecode.

Kind regards,
Carl
--
Carl Rosenberger
db4o - database for objects - http://www.db4o.com


using System;
using System.Reflection;

namespace System {

delegate int IdentityHashCodeProviderDelegate(object obj);

public class IdentityHashCodeProvider {

public static int identityHashCode(object obj) {
if(obj == null){
return 0;
}
return platformDelegate(obj);
}

private static MethodInfo hashMethod;

static IdentityHashCodeProviderDelegate platformDelegate =
createDelegate();

static IdentityHashCodeProviderDelegate createDelegate(){

Assembly assembly = typeof(object).Assembly;

// .NET Framework 1.1
try{
Type t = assembly.GetType(
"System.Runtime.CompilerServices.RuntimeHelpers");
hashMethod = t.GetMethod(
"GetHashCode",
BindingFlags.Public|
BindingFlags.Static);
if(hashMethod != null){
return new IdentityHashCodeProviderDelegate(
IdentityHashCodeProvider.InvokeStatic);
}
}catch(Exception e){}

// CompactFramework
try{
Type t = assembly.GetType("System.PInvoke.EE");
hashMethod = t.GetMethod(
"Object_GetHashCode",
BindingFlags.Public|
BindingFlags.NonPublic|
BindingFlags.Static);
if(hashMethod != null){
return new IdentityHashCodeProviderDelegate(
IdentityHashCodeProvider.InvokeStatic);
}
}catch(Exception e){}

// .NET Framework 1.0
hashMethod = (typeof(System.Object)).GetMethod("GetHashCode");
return new IdentityHashCodeProviderDelegate(
IdentityHashCodeProvider.InvokeObject);
}

static int InvokeObject(object obj){
return (int)hashMethod.Invoke(obj, null);
}

static int InvokeStatic(object obj){
return (int)hashMethod.Invoke(null, new object[] {obj});
}
}
}
 
R

Roman Batoukov [MS]

I'd strongly advise against exploiting internal implementation details
through reflection. This is not supported scenario and there are absolutely
no guarantees it will work with any future versions or service releases of
framework. Also note, that in desktop case you'll need a Reflection
security permission, so your app may not run under some partial trust CAS
policy configurations. .NetCF may support CAS in future releases.

- Roman
 
F

Frank Peschel-Gallée [MS]

First of all, as a more general statement. I would like to second Roman's
advice; it is (almost) guaranteed that this work-around wont work on
upcoming versions of .NETCF.
Secondly (here comes the good news) we will add the desktop's APIs to the
RuntimeServices class, i.e. the code for the desktop and .NETCF would be
identical again. Even better the source code provided by Carl Rosenberger
will continue to work since it tries the "official" (aka the desktop's) way
first.

Thanks
Frank
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top