I have an assembly that contains base objects for my Business Objects, and then another assembly that is automatically generated and populated with classes based off a database schema. The classes in the latter assembly all inherit from a class in the former.
The idea I had was that I could reference the generated assembly from other projects, and 'not' the assembly with the base objects thus hiding some of the implementation details and prohibiting people from using these objects.
Unfortunately, I am realizing that I cannot use any of the functionality built into the base unless I reference it as well. So my question is: Is there anyway around this, and if not then is there a design pattern that addresses this that I should be using?
Question sounds slightly backwards. You are hiding your business/domain layer with your data layer? Generally that would be the other way around.
Either way. The issue sounds like you have:
Assembly A
class Bar
Assembly B
class Foo : Bar
Assembly C must reference both A and B to use Foo.
The design principle to follow would be to favor composition over inheritance.
Rather than Foo inheriting from Bar, Foo could contain an instance of Bar and expose what methods make sense for Foo. This is all assuming that Foo is not actually a specialized version of Bar.
If you really don't want to expose the base classes to others (think extensibility), then you probably should move the bases into the same assembly as the concretes.
If you still need the assemblies separated, you can still make the bases internal, and then set the InternalVisiblesToAttribute on the base class assembly:
(In AssemblyInfo.cs)
using System.Runtime.CompilerServices;
[assembly:InternalsVisibleTo("ConcreteClassAssembly")]
Related
I have an architecture consisting of two DLLs and one executable. Both DLLs define a class with the same name and namespace, but potentially different implementations. What I would like to do is to create an object of each of those classes, and have both of them coexist at the same time.
But as we know a picture says more than a thousand words, so here you go:
The surprising thing is: it actually seems to work!
I have implemented a small prototype using lots of reflection to load the DLLs and instantiate the objects.
Now my question is: Why does this work?
Shouldn't there be a problem having both of the classes in the same AppDomain?
Is it safe to do it this way, or did I just get lucky?
A type is more than its class name and namespace. It also includes assembly information to qualify it. You can compare the AssemblyQualifiedName property of any System.Type and see that they are different.
Okay, I have a solution I am working on that has 4 different projects in it. One of my projects (a console application) is trying to make reference to some of the classes defined in another project (a library); the only problem is, those called are defined as Internal in the library.
How can I use these Internal classes in other assemblies/projects in the same solution? I added references to the library, but that did not help. It is saying that the protection level is too high (because it is internal, it is only available in that assembly).
You generally shouldn't access something that's internal. That defeats the purpose of declaring it so in the first place. If, however, you do need to...
If you can change the assembly with internal things, either:
Make the classes public, or
Use the InternalsVisibleToAttribute to expose it to just the assemblies you want to.
If you cannot change it, or decide not to, then you can use reflection to access the internal classes. For some portions of what you then do with the class, you should be able to use the dynamic keyword to make access easier and faster than with reflection.
You must use reflection to access the internal classes in other assemblies, but it will be significantly slower and not generally optimizable by the compiler. It's also somewhat complicated.
It is recommended that you expose a public class that wraps your internal classes and methods from the other assembly, or simply switch the internal classes in the other assembly over to public.
Is there any spesific reason why e.g. Newtonsoft.Json.JsonIgnoreAttribute is a sealed class? The reason I ask is because I'd like to make wrapper around the Json.Net calls, so that the assembly ref is in one assembly only (makes updating the assembly and testing a bit easier).
Because generally that implies they have (or serve) no purpose being extended/specialized (like many attribute types that exists in the .NET BCL).
I would like to understand a few basics about Assemblies and Namespaces. I've reproduced an NHibernate tutorial, and everything works fine. But I'm not sure if I agree on what classes go where. So look at Solution Explorer image attached..
Domain and Repositories (with classes in folders) are namespaces. And here both are in the ...DAL assembly.
Is there any logical reason to put it there? Product is a POCO class. Shouldn't that more naturally belong outside the DAL assembly?
Is it correct to put IProductRepository in the Domain namespace? And if you suggest to move the POCO classes, would you also move the IProductRepository?
What would I need to do if I wanted to make the DAL usable by both C# and VB.NET projects?
Is there any logical reason to put it
there? Product is a POCO class.
Shouldn't that more naturally belong
outside the DAL assembly?
The argument for putting the POCO class in with the persistence implementation is to simplify deployment and reduce the total number of needed assemblies.
That is not to say I agree with the practice.
It is a better practice, and perhaps even more conventional, to place the definitions of the domain objects in one assembly, and the implementations that depend on the persistence technology in another.
Clients can then reference the assembly of domain object definitions without being tied to the implementation strategy.
Is it correct to put
IProductRepository in the Domain
namespace? And if you suggest to move
the POCO classes, would you also move
the IProductRepository?
Yes, it is correct for the definition of a Repository to be in the Domain.
Repositories are a domain concept, they are not generic - at least not the interface they expose (the implementations may in fact be generic).
The interfaces for the Repository should live with the definitions for the Entities (whether they are POCO's or just interfaces) and with all other domain objects.
What would I need to do if I wanted to
make the DAL usable by both C# and
VB.NET projects?
Nothing special. You can reference the assembly from either C# or VB.Net, whether the DAL and/or Domain assemblies were written in C# or VB.Net. This is a large advantage of .Net as a whole and is quite intentional and by design.
Typically I would put the POCOs in their own library, something like MyProject.Model or "Domain" as you call it. The reason being is that I might want to use them outside of the DAL as well, somewhere higher on the food chain without referencing the DAL assembly. For example I might front the .DataAccess with a .Business project, which will return the same .Model (Domain) objects. Typically my repositories live in MyProject.DataAccess.Repositories for example. You should be able to reference a .NET assembly (no matter if it's C# or VB.NET) from any project without any problems.
I have an interface called IProjectUser that defines a read function and a write function for reading and writing to project files. I also have a class called Project that holds a generic list of IProjectUser objects to manage project files. Both of these are in the class library Project.dll.
I also have a class library called A.dll that contains a class called Foo which implements IProjectUser. The ability to read/write project files is secondary to this class. It holds and manipulates some data. A.dll references Project.dll.
The application also contains some forms and other classes that implement IProjectUser.
I can imagine a situation in the future where I might want to use A.dll in another project that doesn't use project files. However I will be forced to include Project.dll just because A.dll requires it. Even though the functionality is optional.
Is there a different design pattern that would allow me to essentially make an interface optional?
I hope I explained this clearly enough.
Update
What about casting objects to interfaces? This would open up the possibility that an interface is not implemented correctly. Is that a good or bad design approach for this kind of problem?
if (Foo is IProjectUser) {
ProjectUsers.Add(Foo as IProjectUser);
// etc
}
Use inherited or multiple interfaces. You cannot make an interface method optional.
Casting your object to an interface that it doesn't implement will not work -- you'll end up with a null value in your variable. What's wrong with using proper design and adding B.dll as suggested below? A.dll becomes completely reusable, and you still get to have a version of Foo that implements IProjectUser.
Drop the reference to Project.dll from A.dll.
Drop IProjectUser from Foo.
Create B.dll which references Project.dll and A.dll.
Create FooProjectUser in B.dll which inherits from Foo and implements IProjectUser.
Move the project specific logic from Foo into FooProjectUser.
Use FooProjectUser in the places where you currently use Foo, freeing A.dll from any references to Project.dll.