-2

I need to pass the this object by reference in C#. But as you know this is not possible. I have a multi-tier application. In a nutshell, the DAL is getting Data from a web service in JSON Format. The JSON data has to be converted in Business-Layer Objects. Thus, I initialize the Business Layer object and pass it to the DAL. The DAL will convert the data to the object. I show an example of the code. First the DAL:

public Stream  GetSession ( ref BusinessLayer.Session session)
{
    Stream dataStream;
    // Use the ServiceManager to build send the data to the services
    // SOAServiceManager sm = new SOAServiceManager("http://www.Test.da/authentication.json","",DataAccessLayer.HTTPMethod.POST);

    // Add the Values 
    sm.AddCriteriaValue ("name","demo");
    sm.AddCriteriaValue ("password","demo");

    // Now it's show time and the datastream is full
    dataStream = sm.CommitPost ();

    DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(BusinessLayer.Session));

    session = (BusinessLayer.Session)ser.ReadObject(dataStream);

    return dataStream;
}

Now the Business Layer is using this DAL class:

namespace BusinessLayer
{
    public class Session
    {
        public bool Success { get; set; }
        public string Name { get; set; } 

        public Session ()
        {
            DataAccessLayer.Session dal_Session = new DataAccessLayer.Session ();
            dal_Session.GetSession ( ref this);
        }
    }
}

So the problem is, that it is not possible to send "this" as reference. So the solution that I see, is to create a copy object and send it to the DAL and then assign its values to the this object. But that is not a clever solution. Is there a way to solve that in C#?

Tolga Evcimen
  • 7,112
  • 11
  • 58
  • 91
CodeLover
  • 11
  • 1
  • 11
  • I had read that articel, but it is not a solution. As you can see, I have written that this is possible, but it is not clever. In that case the "me" becomes filled, but the "this" object doesn't change. So you have to assign the values of the "me" object again to the "this" object. – CodeLover Mar 18 '14 at 13:45

4 Answers4

4

There is absolutely no need for this if you change the structure of your application.

Let the DAL return a Session, rather than assigning a ref object:

public BusinessLayer.Session GetSession ()
{
    //...
    return (BusinessLayer.Session)ser.ReadObject(dataStream);
}

EDIT There is no need to call that method from the constructor. Obviously, the following still doesn't work:

public Session ()
{
    this = dal.GetSession();
}

However, you could just do the call in the client that calls this constructor. Change

Session session = new Session();

to

Session session = dal.GetSession();

Or, if you want to limit coupling of the client and the dal, you could for instance add a factory method in your Session:

public class Session
{
    //...

    public static Session GetSession()
    {
        return dal.GetSession();
    }
}
Vincent van der Weele
  • 12,927
  • 1
  • 33
  • 61
  • I have tried that before. As you can see in the code the BusinessLayer Session calls the DAL. So if the DAL returns a BL.Session, I have to assign it to the this object like this: this = dal_Session.GetSession (); This doesn't work because I cannot assign to the "this" object. – CodeLover Mar 18 '14 at 13:48
  • @Prog You shouldn't do that anyway. See my edit. – Vincent van der Weele Mar 18 '14 at 13:54
  • The problem with this code is, that you are inserting the DAL code in another layer and the coupling is increasing. So if the user wants to declare a Session object in the UI, it has to use the DAL.GetSession(). But maybe a Factory Pattern is a solution. I have to take a look at it. – CodeLover Mar 18 '14 at 13:59
  • @Prog I see, I added a potential solution with a static factory method. – Vincent van der Weele Mar 18 '14 at 14:08
2

You should not be creating a new Session object. Instead replace DataContractJsonSerializer with Newtonsoft.Json (since the former does not expose such method) and use a method that reads the JSON data and populates an existing object:

using (var reader = new Newtonsoft.Json.JsonTextReader(new StreamReader(dataStream)))
{
    var serializer = new Newtonsoft.Json.JsonSerializer();
    serializer.Populate(reader, session);
}

Alternatively do not use the constructor but instead a static factory method:

public class Session
{
    private Session() { }
    public static Create()
    {
        DataAccessLayer.Session dal_Session = new DataAccessLayer.Session ();
        var session = new Session();
        dal_Session.GetSession (ref session);
        return session;
    }
}
Knaģis
  • 20,827
  • 7
  • 66
  • 80
1

You can just past this as a reference because the object is a reference type.

Ronald Meijboom
  • 1,534
  • 3
  • 17
  • 37
0

Any non-primitive in C# is passed by reference all the time. Consider this code:

public static void Main()
{
    RefType r1 = new RefType();
    RefType r2 = r1;

    r1.Sprop = "hi there";

    Console.WriteLine(r2.Sprop);
}

public class RefType
{
    public string Sprop { get; set; }
}

What do you think the output should be? We never set the Sprop value of the r2 to anything. But r2 was set to be equal to r1, and in both VB.Net and C#, that means both r2 and r1 have the same pointer to the same RefType object that was created.

Thus, The output is "hi there".

So, you don't need to pass this using the ref keyword, because anything that can be referred to as this is a reference type already.

tom.dietrich
  • 8,219
  • 2
  • 39
  • 56
  • I know that. But if you pass this without the ref keyword, you will get an error. So you have to change the function "GetSession ", too and delete the ref keyword. If you do that and pass the "this" object to it, the main "this" object won't change. I tried that out and you can test it, too. – CodeLover Mar 18 '14 at 13:55
  • That error is only caused by the ref keyword in `GetSession`'s arguments, so removing the ref from both locations is the answer. Passing a `ref` to a reference type variable is not doing what you likely think it is doing. Here is a test that shows that you can change a value on the "this" object from another class when passed as an argument: https://ideone.com/dGc4Zq – tom.dietrich Mar 18 '14 at 14:07
  • You are right with that. But here it is a little different. I tried that out. It is little weird. Look: If I pass the "this" object and change the value like this.name = "newValue", it works. But now look at this and try it out: if you pass the "this object and use the (BusinessLayer.Session)ser.ReadObject(dataStream) function, the changed data won't reflect back. And I tried out other cases: if assign "newValue" to the passed object value and after that use this DataContractJsonSerializer.ReadObject function that value changes in the DAL function, but in the BAL it has "newValue"!! – CodeLover Mar 18 '14 at 14:27
  • That problem has little to do with if you're passing a reference to the object (this) or a reference to a reference to the object (ref this). – tom.dietrich Mar 18 '14 at 14:55
  • But I am not passing a reference to a reference but just the "this" object. – CodeLover Mar 19 '14 at 07:02
  • I don't think you really grasp what's going on with the `ref` keyword. – tom.dietrich Mar 19 '14 at 14:26
  • I know exactly what the `ref` keyword does and have used it thousand times in different languages. Maybe you take a look at the `ReadObject(dataStream)` then you will see what I am talking about. – CodeLover Mar 20 '14 at 12:54