Link to home
Start Free TrialLog in
Avatar of SamCash
SamCashFlag for United States of America

asked on

Object Oriented Programming, C#, referencing, scoping.

EE,

I want to NOT pass objects or references in the constructor.  I think the instantiated object should know who instantiated it, and it should be able to scope the instantiator's  objects.  
Object A instantiates Object B.  Can Object B access Object A's  properties, members, etc?

Below is actual sample showing real example.  Advice please?

Kind Regards
Sam

Line 13, I want to NOT pass these objects in the constructor.   Delete lines 13 - 17.
using System;
using System.Web;
using System.Web.SessionState;
using System.Web.UI.WebControls;

namespace prjLogDebug.Utilities
{
    public class Log
    {
        HiddenField _hdnLogDebugChild;
        string _SessionItem;

        public Log(HiddenField hdnLogDebugChild, HttpSessionState Session)
        {
            _hdnLogDebugChild = hdnLogDebugChild;
            _SessionItem = Session["skPost"].ToString();
        }

        public void Append(string message)
        {
            string UrlAbsolute = HttpContext.Current.Request.Url.AbsolutePath;
            DateTimeOffset dt = DateTimeOffset.Now;

            _hdnLogDebugChild.Value = dt.ToString("HH:mm:ss")
            + "-->" + _SessionItem.ToString()
            + ">" + UrlAbsolute
            + "-->" + message
            + "\r\n"
            + _hdnLogDebugChild.Value;
        }
    }
}

Open in new window

One of many webforms:
using prjLogDebug.Utilities;
using System;

namespace prjLogDebug.Site
{
    public partial class wfChild_1 : System.Web.UI.Page
    {
        Log Log;
        
        protected void Page_Load(object sender, EventArgs e)
        {
            if (Session["skPost"] != null)
            {
                Session["skPost"] = (int)Session["skPost"] + 1;
            }
            else
            {
                //Throw err
            }

            hdnLogDebugChild.Value = ""; //clear persisted data from prior post
            Log = new Log(hdnLogDebugChild, Session);

            Log.Append("Child_1 PageLoad()");
        }

        protected void btnLog_Click(object sender, EventArgs e)
        {
            string s = "Text to add from wfChild_1";

            Log.Append(s);

            string result = hdnLogDebugChild.Value; // to view with debugger
        }
    }
}

Open in new window

Avatar of AndyAinscow
AndyAinscow
Flag of Switzerland image

>>Object A instantiates Object B.  Can Object B access Object A's  properties, members, etc?

No, unless you pass an instance of 'A' into 'B' (which you don't want to do).


eg.
class Foo
{
  DoSomething()
  {
     Bar b = new Bar()
     //Why should b know anything about Foo
  }
}

class Wiz
{
  DoSomething()
  {
     Bar b = new Bar()
     //Why should b know anything about Wiz
  }
}

.....  add as many classes here as you like and ask the same question
The question is: Does the object to be initiated require access to the initiating object during initialization? Then yes, you need to pass-in that reference. Either direct by using a ctor parameter or indirect by using a factory/singleton approach.

But why bothering? Testability of your classes? In this case provide a concrete use-case and explain in more detail why you're against ctor params in this case..
Avatar of SamCash

ASKER

Andy,

Thank you for the quick response.  
//Why should b know anything...
I would think (dangerous) "b" would know who instantiated "b", isn't Foo or Wiz's pointer available to "b" and from there be able to scope Foo or Wiz's property, members or fields?

Regards
Sam
Avatar of SamCash

ASKER

ste5an,

Thank you for the prompt comment.  I am new and thought I was doing something inefficient.  If this is proper I will use it as is.

Thanks Again
Sam
>>I would think (dangerous) "b" would know who instantiated "b"...
No, why should it.

One major point of object oriented programming is keeping things together that belong together and separate from everything else
If you need to call functions in an object you need to pass a reference to that object.  (I'm not going to mention the exceptions because that will just confuse matters and are special cases).
it is a quite common requirement that B needs some Information from its creator A.

in a single-threaded  environment A's properties would not change while calling a function of B. so A could pass any Information required from B as function argument to the function. if the property is used in more than one function, B may store the property as an own member. however, this could be dangerous if the property could be changed while B exists. if that is possible or if there are many properties to pass, you may think to collect all those members in an won structure (class) which then indeed is passed by reference to B but also is a member object of A.of course, if you need nearly all properties of A in B (what often is wrong design), you also may pass a reference to A to B. this argument nomally will be called parent. aif class A and class B are not really different but build together a complex class (object), then it is quite normal to pass A as a parent to B. you may think of a container class where a new B element may need to modify head or tail of the container stored in A. then it doesn't make so much sense trying to hide the parent information from element class, if this make the code clumsy and inconvenient to handle.

note, in a multi-threaded Environment, properties of A might change while a function of B was performed. in this case you always should consider to passing references to objects to the B class which would manage access to the properties by making the getters and setters thread-safe.

Sara
Avatar of SamCash

ASKER

ste5an, Sara,

ste5an:
In this case provide a concrete use-case and explain in more detail why you're against ctor params in this case..
 The reason is 1) educational and 2) the practical reason "I do not have to type them all the time on 80+ pages when the params Session and hdnLogDebugChild are always exactly the same."

Best Regards
Sam
In that case (a special case I mentioned in my last comment) a singleton class would be useful for that.
https://msdn.microsoft.com/en-us/library/ff650316.aspx

ps.  This is not about the object knowing about the class that creates it - this is a class with only one instance accessible everywhere
Line 13, I want to NOT pass these objects in the constructor.   Delete lines 13 - 17.
why? you said you  'thought you was doing something inefficient'.

but, on the contrary, if you pass the two arguments in hundreds of calls, it is not efficient. neither for you nor for the compiler.

the design problem is different: if you create a LogDebug object in your code and pass the session and hdnLogDebugChild in the constructor, you then could call the 'Append' member function of your LogDebug to create new debug log messages.

but, if you change to another class you either would need to pass the LogDebug object to the other page, or you have again to create a new LogDebug object passing two arguments in the constructor. if you have 80 pages, it is at least 80 LogDebug objects, or more, if you don't store the newly created LogDebug as member in the page class. if you understand this so far, you may see the way out of the dilemma:

you could create one single LogDebug object in the class where you create the 80 page objects (let us say it was Main class). then pass a reference to the LogDebug to the constructor of all pages. if the pages were not created together but by different functions, you would store the LogDebug object additionally in the Main class such that you could pass it from any Main member function to newly created pages.

so my sggestion is to have

Main
 - creates LogDebug mylog and saves it as a member
 - loop:
   + creates pages and pass mylog by reference to the constructor of the page class

Page Class x
  - creates a copy of the DebugLog passed in the constructor and stores it as member myLog.
  - can call myLog.append(message) where only the message text has to be passed
    as session and hdnLogDebugChild can be taken from the myLog.

MyLog
   - is defined like in your initial post.

Sara
ASKER CERTIFIED SOLUTION
Avatar of ste5an
ste5an
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of SamCash

ASKER

Ste5an,

I wanted to (and tried to) use inheritance.  I thought that was the way to go, from your comment.  I could not figure how to hook it up.  I started this issue Jan 1.  Been working on this solution ever since.  In the meantime I am making new Pages using the "Pass the reference in the constructor technique".  I think I understand (basic) inheritance, I have read a bunch, but obviously I don't understand, or at least understand enough to implement it here.

I would greatly appreciate your assistance in implementing on the above code sample?

Best Regards
Sam