473,473 Members | 1,513 Online
Bytes | Software Development & Data Engineering Community
Create Post

Home Posts Topics Members FAQ

Same Class, different Types

What I'm actually talking about is, when you put the same class in different
assemblies, you get two different types. This is reasonable (if you would
call it) in most cases as it avoids possible misuse. However, what about if
I do want to consider classes with exactly the same definition in different
assemblies to be the same? I tried interpret_cast, but it works only for
trivial scenarios like below:

ref class ClassA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
ClassA^ ca = gcnew ClassA();
ClassB^ cb = reinterpret_cast<ClassB^>(ca);
cb->DoSomething(); // OK, output "From ClassA"
}

However, if you make the scenario more complex by adding some base classes
to ClassA and ClassB, reinterpret_cast fails, as shown below:

interface class InfA
{
DoSomething();
};
interface class InfB
{
DoSomething();
};

ref class ClassA : public InfA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB : public InfB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
InfA^ ca = gcnew ClassA();
InfB^ cb = reinterpret_cast<InfB^>(ca);
cb->DoSomething(); // Oh, an exception "Entry point not found" is thrown
here.
}

In standard C++, I don't think there will be any problem with the above
attempt. However, in C++/CLI, well, I'm waiting for your reply...

Born
Mar 30 '07 #1
8 1846
Native C++ has no such problem because the types do not have a "strong
name". Types in managed assemblies, on the other hand, have a "strong name"
which means that type X in one assembly is not the same as type X in another
assembly, because their strong names are different.

You mention different assemblies. Are the two assemblies somehow related or
completely unrelated?

If they are completely unrelated then you might want to factor out the
shared types into a third assembly and have both of the other assemblies
depend on types defined within it. That way they are both using the same
strong name, hence referring to the same type.

If they are related then one of the assemblies should control the class
definition and the other assembly should use it. That way they are both
using the same type definition.

Kevin.
"Born Bugler" <wo*******@263.netwrote in message
news:eu**********@news.yaako.com...
What I'm actually talking about is, when you put the same class in
different assemblies, you get two different types. This is reasonable (if
you would call it) in most cases as it avoids possible misuse. However,
what about if I do want to consider classes with exactly the same
definition in different assemblies to be the same? I tried interpret_cast,
but it works only for trivial scenarios like below:

ref class ClassA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
ClassA^ ca = gcnew ClassA();
ClassB^ cb = reinterpret_cast<ClassB^>(ca);
cb->DoSomething(); // OK, output "From ClassA"
}

However, if you make the scenario more complex by adding some base classes
to ClassA and ClassB, reinterpret_cast fails, as shown below:

interface class InfA
{
DoSomething();
};
interface class InfB
{
DoSomething();
};

ref class ClassA : public InfA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB : public InfB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
InfA^ ca = gcnew ClassA();
InfB^ cb = reinterpret_cast<InfB^>(ca);
cb->DoSomething(); // Oh, an exception "Entry point not found" is
thrown here.
}

In standard C++, I don't think there will be any problem with the above
attempt. However, in C++/CLI, well, I'm waiting for your reply...

Born

Mar 30 '07 #2
They are unrelated. I know exactly your solution. But what if I don't want a
third assembly? In many cases the third assembly would be filled with only
interfaces, and it looks silly to maintain a separate assembly for that
purpose.
"Kevin Frey" <ke**********@hotmail.comwrote in message
:Om**************@TK2MSFTNGP05.phx.gbl...
Native C++ has no such problem because the types do not have a "strong
name". Types in managed assemblies, on the other hand, have a "strong
name" which means that type X in one assembly is not the same as type X in
another assembly, because their strong names are different.

You mention different assemblies. Are the two assemblies somehow related
or completely unrelated?

If they are completely unrelated then you might want to factor out the
shared types into a third assembly and have both of the other assemblies
depend on types defined within it. That way they are both using the same
strong name, hence referring to the same type.

If they are related then one of the assemblies should control the class
definition and the other assembly should use it. That way they are both
using the same type definition.

Kevin.
"Born Bugler" <wo*******@263.netwrote in message
news:eu**********@news.yaako.com...
>What I'm actually talking about is, when you put the same class in
different assemblies, you get two different types. This is reasonable (if
you would call it) in most cases as it avoids possible misuse. However,
what about if I do want to consider classes with exactly the same
definition in different assemblies to be the same? I tried
interpret_cast, but it works only for trivial scenarios like below:

ref class ClassA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
ClassA^ ca = gcnew ClassA();
ClassB^ cb = reinterpret_cast<ClassB^>(ca);
cb->DoSomething(); // OK, output "From ClassA"
}

However, if you make the scenario more complex by adding some base
classes to ClassA and ClassB, reinterpret_cast fails, as shown below:

interface class InfA
{
DoSomething();
};
interface class InfB
{
DoSomething();
};

ref class ClassA : public InfA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB : public InfB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
InfA^ ca = gcnew ClassA();
InfB^ cb = reinterpret_cast<InfB^>(ca);
cb->DoSomething(); // Oh, an exception "Entry point not found" is
thrown here.
}

In standard C++, I don't think there will be any problem with the above
attempt. However, in C++/CLI, well, I'm waiting for your reply...

Born


Mar 30 '07 #3
Hi Born!
ref class ClassA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
ClassA^ ca = gcnew ClassA();
ClassB^ cb = reinterpret_cast<ClassB^>(ca);
cb->DoSomething(); // OK, output "From ClassA"
}
You should use "Reflection" to call the "DoSomething" method!

Greetings
Jochen
Mar 30 '07 #4
Oh, no, Jochen.

Please give me a detailed solution. Personally, I would say it will be much
harder than you have thought.

Born
"Jochen Kalmbach [MVP]" <no********************@holzma.deWrote in
message:%2****************@TK2MSFTNGP06.phx.gbl...
Hi Born!
>ref class ClassA
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassA" ); }
};

ref class ClassB
{
public:
virtual DoSomething(){ Console::WriteLine( "From ClassB" ); }
};

int main()
{
ClassA^ ca = gcnew ClassA();
ClassB^ cb = reinterpret_cast<ClassB^>(ca);
cb->DoSomething(); // OK, output "From ClassA"
}

You should use "Reflection" to call the "DoSomething" method!

Greetings
Jochen

Mar 30 '07 #5
Hi Born!
Oh, no, Jochen.

Please give me a detailed solution. Personally, I would say it will be much
harder than you have thought.

Regardless, that the "correct solution" is to put the "common" class in
a common-assembly, you can use refelction:

namespace Foo
{
ref class A
{
public: void DoSomething() {
System::Console::WriteLine("A::DoSomething"); }
};

ref class B
{
public: void DoSomething() {
System::Console::WriteLine("B::DoSomething"); }
};

ref class General
{
public: void static DoSomething(Object ^instance)
{
if (instance == nullptr) throw gcnew
System::NullReferenceException("'instance' must be set!");
System::Type ^t = instance->GetType();
System::Reflection::MethodInfo ^mi = t->GetMethod("DoSomething",
gcnew array<System::Type^{});
if (mi == nullptr) throw gcnew
System::MethodAccessException("Method 'DoSomething' not found!");
mi->Invoke(instance, gcnew array<Object^{});
}
};
}

int main()
{
Foo::A ^a = gcnew Foo::A();
Foo::B ^b = gcnew Foo::B();

Foo::General::DoSomething(a);
Foo::General::DoSomething(b);
}

Greetings
Jochen
Mar 30 '07 #6
So you misunderstood me.

I want to change an object from TypeA to TypeB, assuming TypeA and TypeB are
samely structured (with same methods, properties and so on. In most cases,
TypeA and TypeB will be interfaces. )

I'm almost sure this is unfeasible under .NET framework, especially if I
don't want to pay much performance penalty. If the performance is not taken
into consideration, through, there might be some ways:

1) Use wrapper objects.

The wrapper object will be derived from TypeB, and wrap the original TypeA
object.

2) Change the metadata of the original object to make it a real TypeB object
(sounds crazy).

Born
"Jochen Kalmbach [MVP]" <no********************@holzma.deWrote in
message:en**************@TK2MSFTNGP02.phx.gbl...
Hi Born!
>Oh, no, Jochen.

Please give me a detailed solution. Personally, I would say it will be
much harder than you have thought.


Regardless, that the "correct solution" is to put the "common" class in a
common-assembly, you can use refelction:

namespace Foo
{
ref class A
{
public: void DoSomething() {
System::Console::WriteLine("A::DoSomething"); }
};

ref class B
{
public: void DoSomething() {
System::Console::WriteLine("B::DoSomething"); }
};

ref class General
{
public: void static DoSomething(Object ^instance)
{
if (instance == nullptr) throw gcnew
System::NullReferenceException("'instance' must be set!");
System::Type ^t = instance->GetType();
System::Reflection::MethodInfo ^mi = t->GetMethod("DoSomething",
gcnew array<System::Type^{});
if (mi == nullptr) throw gcnew System::MethodAccessException("Method
'DoSomething' not found!");
mi->Invoke(instance, gcnew array<Object^{});
}
};
}

int main()
{
Foo::A ^a = gcnew Foo::A();
Foo::B ^b = gcnew Foo::B();

Foo::General::DoSomething(a);
Foo::General::DoSomething(b);
}

Greetings
Jochen

Mar 31 '07 #7
Hi Born!
So you misunderstood me.
No. "reinterpret_cast" ist not possible in a "strong typed system".
So the only way is to use reflection, and this works very well (but slow).

But in most cases: if you have a bad design, you mostly must use a bad
solution ;)

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/
Mar 31 '07 #8
Born Bugler wrote:
They are unrelated. I know exactly your solution. But what if I don't want a
third assembly?
For your problem, the right way to do is to have a dedicated assembly
with the interfaces only. In .NET, it's perfectly normal to have an
assembly for a group of classes that belong together. Especially so if
those classes are stable and won't be expected to change.

Without doing that, you have to live with an imperfect and awkward
solution, such as reflection, as others have pointed it out.
In many cases the third assembly would be filled with only
interfaces, and it looks silly to maintain a separate assembly for that
purpose.
It's not silly. The .NET framework itself is broken into 100s of assemblies.

If you want to design a plugin architecture, publish all the interfaces
in an assembly. It's self-contained, and that's *all* plugin
implementors will ever need in order to write custom modules for your
system. It's a good design, it's not silly.

If you have a small group of classes that you consider stable, it's a
very good idea to move them into an assembly, even if that DLL will only
have 3 functions. This approach fosters stability in the long run. Every
time you have to recompile code, you run the risk of breaking something,
and you must retest your entire package from sratch. A well tested,
compiled, self-described binary module that never changes is as stable
as it gets. You can even reuse that in other projects.

Tom
Apr 2 '07 #9

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

12
by: williamc | last post by:
Is there anything wrong with having several classes with the same name in the same style sheet? Something like... div.pagedown { margin: 20px 0px 20px 0px; border-top: 1px solid #caa;...
13
by: Dan Tsafrir | last post by:
is the following code standard? (cleanly compiles under g++-4.0.2): struct Asc { bool operator()(int a, int b) {return a < b;} }; struct Des { bool operator()(int a, int b) {return b > a;} };...
9
by: Ryan Taylor | last post by:
Hello. I am trying to overload a method so that I have four possible working copies. The only difference between the four methods is what to search by and in what manner to return the results....
5
by: Joe Black | last post by:
Hi all, Using Windows CP Pro VS .net 2005 I'm creating an app that allows user to extend its functionality by installing plug in modules, these modules support an interface I have created...
9
by: David A. Osborn | last post by:
I have a set of classes that each have an enumeration in them, and based on dynamic input I need to access a different enumeration. For example Three classes Class_A, Class_B, and Class_C that...
4
by: Dan Krantz | last post by:
I have the following template to ensure that a given number (val) falls into a range (between vmin & vmax): template<typename T> T ForceNumericRange( const T& val, const T& vmin, const T& vmax)...
1
by: Senthryl | last post by:
I just moved from Visual Basic to C++ and recently finished reading my book. However, I'm trying to implement something which has led me to writing the same thing many times, which I've learned is...
70
by: garyusenet | last post by:
I'm using an example piece of code: - namespace Wintellect.Interop.Sound{ using System; using System.Runtime.InteropServices; using System.ComponentModel; sealed class Sound{ public static...
7
by: WTH | last post by:
I am now aware (I am primarily a C++ developer) that in C# if you reference the same interface from the same file in two different projects the types are actually incompatible. I found this out...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
1
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
1
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...
0
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
0
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated ...
0
muto222
php
by: muto222 | last post by:
How can i add a mobile payment intergratation into php mysql website.

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.