-1

I am working with some Legacy code. I general method that I usually would call like this:

Poco = MyMethod(Poco.Id) // Lookup PocoToReturn on Poco.Id and return PocoToReturn

are called in my Legacy like this:

MyLegacyMethod(Poco) // Lookup lookedUpPoco on Poco.Id, set Poco = lookedUpPoco and return (void)

The later work mostly but not always. I am struggling to understand when the later work and where it does not works (and should be fixed)

Consider the following execution of the code I are located at the end of this post:

  1. Facade.AppleFacade.GetApple() is called
  2. Persist.ApplePersist.GetAppleInfo(appleInfo) is called
  3. info = new AppleInfo { Id = "newId", Name = "Test"} is executed
  4. GetAppleInfo in the persist returns to GetApple in the facade

Expected: Info.Id = "newId" and Info Name = "test"

Actual: Info.Id = "oldId" and Info Name = null

If I add ref to get MyStrangeMethod(ref Poco) the my Actual will be as Expected. I guess

I have 2-3 Questions:

  • Why is ref neccessary in this case then other code wihtout ref is working without problems?
  • In general, what is the difference between using ref and using no prefix for Objects of different type?
  • (I think I know the answer to this) Why do I calls like MyMethod(ref myPoco.myProperty) result in compile time error A property or indexer may not be passed as an out or ref parameter

Below the code example I mention above

namespace Facade
{
    public class AppleFacade
    {
        public AppleInfo GetApple()
        {
            var appleInfo = new AppleInfo();
            appleInfo.Id = "oldId";
            _applePersist.LoadAppleInfo(appleInfo);
            return appleInfo;
        }
    }
}

namespace Persist
{
    public class ApplePersist
    {
        public void GetAppleInfo(AppleInfo info)
        {
            info = new AppleInfo
            {
                Id = "id",
                Name = "test"                
            };
        }
    }
}   
  • Unless there's some behind the scenes trickery, your legacy code should never work. I.E., `MyLegacyMethod(Poco) { set Poco = lookedUpPoco; return (void); }` should never be able to overwrite the caller's Poco object. If you think that it is, then please try to provide a minimal example that demonstrates this. – RBarryYoung Apr 03 '21 at 15:13

1 Answers1

0

In C# class instances are reference types and structs are value type (primitive types are value type too). A variable of a reference type does not contain its data directly; it contains a reference to its data. When you pass a reference type to a method you pass its reference value.

So, in GetAppleInfo you receive a new reference for the appleInfo object and you simple overwrite that with a new reference of the new AppleInfo instance. This clearly does not change anything in the caller. Your example is analogous to this:

AppleInfo appleInfo = new AppleInfo{ Name = "A"};
AppleInfo info = appleInfo; 
info = new AppleInfo{ Name = "B"};
// appleInfo.Name == "A" 

If you pass a reference type by reference using ref (or out) then you are passing its reference by reference instead of value. This would be analogue to this:

AppleInfo a = new AppleInfo{ Name = "A"};
a = new AppleInfo{ Name = "B"};
// a.Name == "B" 
blow
  • 12,811
  • 24
  • 75
  • 112