C# Accessing a class from a "parent project" in a "child project"? - c#

Let's say I have multiple projects within a solution. I have the main project parent_project and another project child_project.
How can I access classes / namespaces residing in parent_project from child_project ?
I have already added a Reference to child_project in parent_project so I can't add a Reference to parent_parent in child_project as it would create a circular dependency.
Is this possible?

If you're sharing logic between projects, you need to isolate that dependency and move it to a shared location (new project for example), restructure your dependencies so that your core logic lives in a core domain-like project or mash your projects together.
The latter is not really the cleanest of solutions. I would recommend thinking about your own question and really try to answer "Why do I NEED a circular reference? How can I restructure so that my dependencies make sense?".

You can inject your dependency using an interface defined in the child project (this can be useful where major refactoring is not possible/too expensive).
e.g. In the child project:
interface IA {
DoLogicInB();
}
In the parent project:
class ConcreteA : ChildProject.IA
{
DoLogicInB() { ... }
}
In the child project, where you need the logic:
class ChildB {
void DoSomethingWithParent(IA logicEngine) {
logicEngine.DoLogicInB();
}
}
You need to then be able to inject a concrete implementation of the parent object from outside the child project.

FYI
I ended up just copying the logic to a shared location, and "child" projects can access this version. I know from a maintainability point of view this isn't the best solution but it seemed like the best compromise..

I didn't require entire namespace, but just reading some data dictionary or calling one particular method from parent project class. Here is how we got it working.
using System;
using NUnit.Framework;
using System.Collections.Concurrent;
namespace MyProject.tests
{
public class ParentChildTest
{
[Test]
public void dataAndMethodTest()
{
// add the data in parent project
Parent.propertyCache["a"] = "b";
// read the data in child project
Console.WriteLine("Read from child: " + Child.getProperty("a"));
// use Child project to call method of parent project
Console.WriteLine("Call from child: Populate method in parent: " + Child.populate("c"));
}
}
class Parent
{
// data is in Child project. Parent project just has the reference.
public static ConcurrentDictionary<string, string> propertyCache = Child.getPropertyCache();
public static string populate(string key)
{
//calculation
string value = key + key;
propertyCache[key] = value;
return value;
}
// Pass the parent project method reference to child project
public static int dummy = Child.setPopulateMethod(populate);
}
class Child
{
// data store
static ConcurrentDictionary<string, string> propertyCache = new ConcurrentDictionary<string, string>();
public static ConcurrentDictionary<string, string> getPropertyCache()
{
return propertyCache;
}
public static string getProperty(string key)
{
if (propertyCache.ContainsKey(key))
{
return propertyCache[key];
}
return null;
}
// reference to parent project method
static Func<string, string> populateMethodReference = null;
public static int setPopulateMethod(Func<string, string> methodReference)
{
populateMethodReference = methodReference;
return 0;
}
public static string populate(string key)
{
return populateMethodReference(key);
}
}
}
Using parent project class data in child
Earlier the propertyCache was in parent class. Child needed to access it.
So, the propertyCache has been moved to Child. Parent also reads and populates the same.
Using parent project class method in child
Pass the method reference to the child somehow (by some static method).
use the reference to invoke that parent method.
Output of the program
Read from child: b
Call from child: Populate method in parent: cc

I have to say that Yannicks answer is the way to go there normally. In your special situation (as outlined in your comment to his answer) it sounds like that would be problematic. A different way would be (only possible if the mainclass compiles into a dll):
Include the compiled dll of the mainproject in the child project
Use the methods you need via reflection
This is one possible other route BUT has quite a few pitfalls as reflection has troubles of its own.

Ok so let's say you have a Project with 2 solution in it S1 and S2 and you have reference S1 in S2, inside S1 it you have a class P and in S2 you have three Class defined by user A B an C. now make A inherit P so when you invoke constructor of A it will invoke constructor of P (that's in In S1) noe inside P's Constructor if you want the list of all the class declared in S2 use this code.
Assembly assembly = this.GetType().Assembly;
// DefinedTypes will list all Userdefined class
foreach (var typeInfo
inassembly.DefinedTypes )
{
// typeInfo.FullName //you will have A B and C
}

Related

Why is my newly created method not appearing in a different class that has a reference to the class to which the method belongs?

I have 2 projects in my asp.net C# solution. One project is 'AeS.PIMS_Education_2275.IL' and the other is 'AeS.PIMS_Education_2275.PL'. I just created a new method in a class called 'PIMS_Education_IL_2275' belonging to 'AeS.PIMS_Education_2275.IL'. The project 'AeS.PIMS_Education_2275.PL' has a reference to 'AeS.PIMS_Education_2275.IL', but when I create an object of the class 'PIMS_Education_IL_2275' inside the class 'PIMS_Education_2275' of 'AeS.PIMS_Education_2275.PL' and try to access the methods in it, I am able to access all methods apart from the newly created method. What might be wrong here ? Below are the code snippets:
Class - AeS.PIMS_Education_2275.IL
namespace AeS.PIMS_EducationDetails_IL_2275
{
public class PIMS_Education_IL_2275
{
public DataSet ValidateEducationDiscipline() //newly created method
{}
}
}
Class - PIMS_Education_2275
using AeS.PIMS_EducationDetails_IL_2275;
namespace AeS.PIMS_Education_2275.PL
{
public partial class PIMS_Education_2275
{
public bool FormValidation()
{
PIMS_Education_IL_2275 o = new PIMS_Education_IL_2275(); //Creating an object
o.ValidateEducationDiscipline(); //Not able to call the method here
}
}
}
Additional information - I had just one project in the solution initially and then added the second one in which I created a new method.
Screen shots of dependencies:
1) Use the project reference instead of direct reference.
2) verify the build order of the solution. The project AeS.PIMS_Education_2275.IL should build first and then AeS.PIMS_Education_2275.PL

Load same assembly second time with clean static variables

I have a .dll library, which I cannot modify, with classes which uses many static variables and singleton instances.
Now I need a second instance of all these classes and I need some solution which would isolate static variables between instances of some class without altering any other properties of the assembly.
Loading the same assembly second time doesn't actually load it again, but I found that reading it to byte array and then loading it, actually solves half of the problem:
lib.dll:
namespace lib
{
public class Class1 : ILib
{
private static int i;
public int DoSth()
{
return i++;
}
public string GetPath()
{
return typeof(Class1).Assembly.Location;
}
}
}
app.exe:
namespace test
{
public interface ILib
{
int DoSth();
string GetPath();
}
class Program
{
static void Main()
{
var assembly1 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance1 = (ILib)assembly1.CreateInstance("lib.Class1");
Console.WriteLine(instance1.GetPath());
Console.WriteLine(instance1.DoSth());
Console.WriteLine(instance1.DoSth());
var assembly2 = Assembly.LoadFile(Path.GetFullPath(".\\lib.dll"));
var instance2 = (ILib)assembly2.CreateInstance("lib.Class1");
Console.WriteLine(instance2.GetPath());
Console.WriteLine(instance2.DoSth());
Console.WriteLine(instance2.DoSth());
var assembly3 = AppDomain.CurrentDomain.Load(File.ReadAllBytes("lib.dll"));
var instance3 = (ILib)assembly3.CreateInstance("lib.Class1");
Console.WriteLine(instance3.GetPath());
Console.WriteLine(instance3.DoSth());
Console.WriteLine(instance3.DoSth());
Console.Read();
}
}
}
this returns:
C:\bin\lib.dll
0
1
C:\bin\lib.dll
2
3
0
1
Static variables got restarted but unfortunately the next problem is that assembly location which is used within the library is empty.
I would like to avoid loading the library to different AppDomain because it creates too many problems with cross domain code; some classes are not serializable.
I would like to avoid physically copying the library on disk.
I would like to avoid IL weaving and using Mono.Cecil or similar because it's an overkill.
Loading assembly into separate AppDomain or separate process are only sensible options you have. Either deal with cross-domain/cross-process communication or get version of library that does not have problems you trying to work around.
If you want to fix your load from bytes you'd need to read all articles around https://blogs.msdn.microsoft.com/suzcook/2003/09/19/loadfile-vs-loadfrom/.

Multiple Assemblies with the same API

I have three assemblies, A.dll, B.dll, C.dll that all define a single namespace A, B, C and a single class A, B, C.
The classes in each assembly have the exact same API, identical in every way.
I now need to write an application that uses all three assemblies and I am struggling to find the best way to do this.
For example the classes define the following function:
string GetName();
In my application I have a matching function, but how can I simplify the implementation?
A MyA = new A();
B MyB = null;
C MyC = null;
public string GetName() {
if (MyA != null) return MyA.GetName();
else if (MyB != null) return MyB.GetName();
else if (MyC != null) return MyC.GetName();
}
I have a lot of functions in this API so it would be messy to do this if/else over and over again.
Interfaces
I thought about defining an interface for the API, but I don't want to add another assembly that my application and these three assemblies are dependent on. I also don't want to create an inter-dependency between any of these assemblies. This is because the assemblies are used individually in other situations that unfortunately only allow for a single assembly, which is out of my control.
Reflection
I thought about using reflection and delegates:
private void GetAPI() {
var Api = MyA;
Type t = Api.GetType();
System.Reflection.MethodInfo m = t.GetMethod("GetName");
_GetName = (GetNameDelegate)Delegate.CreateDelegate(typeof(GetNameDelegate), Api, m);
}
public string GetName() {
return _GetName();
}
This works, but how do I expand this to re-use this piece of code for all three assemblies? I.e. how to pass in MyA, MyB, MyC into the GetAPI function?
Thanks!
Assuming you can't go about this using standard OOP patterns (interface, inheritance), you could make some helper methods to avoid writing lots of code to invoke your delegates. For example, these methods below allow you to do expressions like this on your Api classes:
var nameForApiA = Wrapper.Invoke<ApiA, string>(apiA => apiA.GetName());
Note that this calls Activator.CreateInstance on the type parameter, so if your API classes have constructor parameters, those will need to be handled another way.
public class Wrapper
{
public static void Invoke<TApi>(Action<TApi> method)
{
var instance = Activator.CreateInstance<TApi>();
method.Invoke(instance);
}
public static TReturn Invoke<TApi, TReturn> (Expression<Func<TApi, TReturn>> method)
{
var instance = Activator.CreateInstance<TApi>();
Func<TApi, TReturn> compiled = method.Compile();
return compiled(instance);
}
}
I suggest to create an Interface. And use the interface instead of the actual class. Another way is to create and an Abstact Class and ovverrid all the function for each class of yours

Is this one of them circular references?

I want to add an easily accessible helper class to my asp mvc page. I created a class called Repositories. It has a static property "Current" which does the following:
public static readonly Repositories Current
{
get
{
if(HttpContext.Current.Items["Repositories"] == null)
HttpContext.Current.Items["Repositories"] = new Repositories(HttpContext.Current);
return (Repositories)HttpContext.Current.Items["Repositories"];
}
}
The point is that the class has static helper functions that use the current instance of the class (tied to current httpcontext). The helper functions do all kinds of stuff, the reason I wanted to organize them like this is because it makes for a nicer looking code in the controllers and i have potential access to all database repositories (the actual handle objects are created only if accessed in this context though).
Anyway, as you can see, the constructor takes a HttpContext as an argument, which is then stored in a private class field so I'd have less to type. This means that the Repositories class instance refers to HttpContext class instance and vice-versa. When the HttpContext is dropped, does this mean that it still sticks around in the memory, being preserved by a circular-reference by the Repositories instance?
An "orphaned" circular reference doesn't force objects to stay around in memory.
If you do this:
class A
{
public B b;
~A()
{
Console.WriteLine("COLLECTED A!");
}
}
class B
{
public A a;
~B()
{
Console.WriteLine("COLLECTED B!");
}
}
and run this code:
var a = new A();
var b = new B();
a.b = b;
b.a = a;
a = null;
b = null;
GC.Collect();
Both instances can (and will) be garbage collected. You will get something similar to the following output:
COLLECTED B!
COLLECTED A!

expose a referenced type (class) without need for additional reference

I have a layered system of .dlls between my application, where the lowest level has a class that provides certain functionality - an instance of this class can be received through a GetClass() function and then I can access its properties (basically, a collection of information of changing objects).
Now I noticed that when I want to access that information from the next higher level .dll, the compiler complains that I do not have the lower level .dll referenced (the one defining the class) - which actually I would want to avoid, to have a nice layered structure in my architecture.
How to get around this? Can I re-expose the referenced type? Do I really have to write a wrapper of my own, if I want exactly the same functionality? Or do I even need to reference the low level .dll again?
DLL 1:
class myClass;
myClass GetMyClass();
DLL 2:
myClass GetMyClass();
EXE:
How to access result from calling GetMyClass (DLL 2) without referencing DLL 1?
You need to separate all the common classes you use across all your layers into a new dll, then reference this dll on every project.
Try to use interfaces so you can work over the contract (the functionality) instead of the concrete implementation. It will help you to avoid unnecessary references.
// common dll
public interface IMyClass
{
string MyData { get; set; }
IMyClass GetMyClass();
}
// dll1
public class myClass : IMyClass
{
public string MyData { get; set; }
public IMyClass GetMyClass() { return new myClass() { MyData = "abc" }; }
}
// dll2
public class myClass2
{
public IMyClass GetMyClass()
{
var c1 = new myClass();
var c2 = c1.GetMyClass();
return c2;
}
}
// exe (references common and dll2)
public class Program
{
public static void Main(string[] args)
{
var c1 = new myClass2();
IMyClass c2 = c1.GetMyClass();
Console.Writeline(c2.MyData);
}
}
Seems no way to achieve this, if myClass is defined in dll1, since objects of type myClass may be instantiated at runtime. To avoid this, you need to change the return type of GetMyClass() in dll2 to return something defined in dll2. It can be a class quite similar to myClass and having the same properties (you can even use tools like AutoMapper to easily convert between objects), but it definitely should be in dll2. Something like:
// dll1
class myClass
{
...
}
myClass GetMyClass()
{
...
}
// dll2
class myClass2
{
public myClass2(myClass c)
{
// instantiate myClass2 with values from myClass
}
}
myClass2 GetMyClass()
{
// somehow get myClass and convert it to myClass2 here
}
We do something similar to this in our local code. You can load the assembly at runtime, scan the types it contains using reflection, and again using reflection call functions and instantiate types from that dll, without ever referencing it directly in the project.
some of the key functions you will need are:
Assembly.LoadFrom(path); //get the assembly as a local object
Activator.CreateInstance(type); //create an instance of a type
Assembly.GetType(string);//fetch a type by name from the assembly
Once you have the type, basic reflection will give you pretty much every other piece you need.
Here is the snippet from my local code:
asm = Assembly.LoadFrom(Path.Combine(Environment.CurrentDirectory, filePath));
Type[] types = asm.GetTypes();
for (var x = 0; x < types.Length; x++)
{
var interfaces = types[x].GetInterfaces();
for (var y = 0; y < interfaces.Length; y++)
{
if (interfaces[y].Name.Equals("MyTypeName"))
{
isValidmod = true;
var p = (IMyType)Activator.CreateInstance(types[x]);
//Other stuff
}
}
Also note: this is pretty old code now. It has been neither reviewed nor refactored in years, so its essentially modern as of .NET 1.1, BUT: It illustrates the point. How to load a type from a remote assembly that is NOT locally referenced.
Additionally, this is part of an engine that loads some 50 of these, given a rigid folder structure, which is why its so generic looking. Take what you need from it.
The caller must have a reference to the class in DLL1 to know what type it is accessing. So yes you need to reference the first dll in the exe. Since GetMyClass() returns a type in DLL1 the type needs to be exposed in the exe, therefore dll1 must be referenced.
I go with Nick using any Ioc framework like spring.net or microsoft unity. to get the idea properly go through http://martinfowler.com/articles/injection.html
One solution here is to provide a 4th DLL that contains interfaces for your classes. You would reference this in all 3 of your layers, and return these interfaces instead of your classes.
This should give you a good idea of what I mean:
// DLL1
class ClassInDLL1 : IClassInDLL1
{
}
// DLL2
class ClassInDLL2
{
public IClassInDLL1 GetClassInDLL1()
{
return new ClassInDLL1();
}
}
// DLL3
class ClassInDLL3
{
public void DoSomething()
{
var dll2 = new ClassInDLL2();
var dll1 = dll2.GetClassInDLL1(); // dll1 variable is of type IClassInDLL1
// do stuff with dll1
}
}
// interface DLL
interface IClassInDLL1
{
}
I'll be honest though, layering your architecture like this is usually not an awesome idea unless your project is really large. I find that artificially making assembly splits like this ahead of time can cause you unnecessary pain, not to mention the fact that you end up with 3-4 assemblies for a medium or small project that might only need 1.

Categories

Resources