Can I detect whether I've been given a new object as a parameter?

我们两清 提交于 2019-12-01 17:09:54

No, basically.

There's really no difference between:

var x = new ...;
Foo(x);

and

Foo(new ...);

and indeed sometimes you might convert between the two for debugging purposes.

Note that in the DataRow/DataTable example, there's an alternative approach though - that DataRow can know its parent as part of its state. That's not the same thing as being "new" or not - you could have a "detach" operation for example. Defining conditions in terms of the genuine hard-and-fast state of the object makes a lot more sense than woolly terms such as "new".

Yes, there is a way to do this.

Sort of.

If you make your parameter a ref parameter, you'll have to have an existing variable as your argument. You can't do something like this:

DoSomething(ref new Customer());

If you do, you'll get the error "A ref or out argument must be an assignable variable."

Of course, using ref has other implications. However, if you're the one writing the method, you don't need to worry about them. As long as you don't reassign the ref parameter inside the method, it won't make any difference whether you use ref or not.

I'm not saying it's good style, necessarily. You shouldn't use ref or out unless you really, really need to and have no other way to do what you're doing. But using ref will make what you want to do work.

No. And if there is some reason that you need to do this, your code has improper architecture.

Short answer - no there isn't

In the vast majority of cases I usually find that the issues that you've listed above don't really matter all that much. When they do you could overload a method so that you can accept something else as a parameter instead of the object you are worried about sharing.

// For example create a method that allows you to do this:
people.Add("Larry");

// Instead of this:
people.Add(new Person("Larry"));

// The new method might look a little like this:
public void Add(string name)
{
    Person person = new Person(name);
    this.add(person); // This method could be private if neccessary
}

I can think of a way to do this, but I would definitely not recommend this. Just for argument's sake.

What does it mean for an object to be a "new" object? It means there is only one reference keeping it alive. An "existing" object would have more than one reference to it.

With this in mind, look at the following code:

    class Program
    {
        static void Main(string[] args)
        {
            object o = new object();

            Console.WriteLine(IsExistingObject(o));
            Console.WriteLine(IsExistingObject(new object()));

            o.ToString();  // Just something to simulate further usage of o.  If we didn't do this, in a release build, o would be collected by the GC.Collect call in IsExistingObject. (not in a Debug build)
        }

        public static bool IsExistingObject(object o)
        {
            var oRef = new WeakReference(o);

#if DEBUG 
            o = null; // In Debug, we need to set o to null.  This is not necessary in a release build.
#endif
            GC.Collect();
            GC.WaitForPendingFinalizers();

            return oRef.IsAlive;
        }
    }

This prints True on the first line, False on the second. But again, please do not use this in your code.

Let me rewrite your question to something shorter.

Is there any way, in my method, which takes an object as an argument, to know if this object will ever be used outside of my method?

And the short answer to that is: No.

Let me venture an opinion at this point: There should not be any such mechanism either.

This would complicate method calls all over the place.

If there was a method where I could, in a method call, tell if the object I'm given would really be used or not, then it's a signal to me, as a developer of that method, to take that into account.

Basically, you'd see this type of code all over the place (hypothetical, since it isn't available/supported:)

if (ReferenceCount(obj) == 1) return; // only reference is the one we have

My opinion is this: If the code that calls your method isn't going to use the object for anything, and there are no side-effects outside of modifying the object, then that code should not exist to begin with.

It's like code that looks like this:

1 + 2;

What does this code do? Well, depending on the C/C++ compiler, it might compile into something that evaluates 1+2. But then what, where is the result stored? Do you use it for anything? No? Then why is that code part of your source code to begin with?

Of course, you could argue that the code is actually a+b;, and the purpose is to ensure that the evaluation of a+b isn't going to throw an exception denoting overflow, but such a case is so diminishingly rare that a special case for it would just mask real problems, and it would be really simple to fix by just assigning it to a temporary variable.

In any case, for any feature in any programming language and/or runtime and/or environment, where a feature isn't available, the reasons for why it isn't available are:

  • It wasn't designed properly
  • It wasn't specified properly
  • It wasn't implemented properly
  • It wasn't tested properly
  • It wasn't documented properly
  • It wasn't prioritized above competing features

All of these are required to get a feature to appear in version X of application Y, be it C# 4.0 or MS Works 7.0.

Nope, there's no way of knowing.

All that gets passed in is the object reference. Whether it is 'newed' in-situ, or is sourced from an array, the method in question has no way of knowing how the parameters being passed in have been instantiated and/or where.

One way to know if an object passed to a function (or a method) has been created right before the call to the function/method is that the object has a property that is initialized with the timestamp passed from a system function; in that way, looking at that property, it would be possible to resolve the problem.

Frankly, I would not use such method because

  • I don't see any reason why the code should now if the passed parameter is an object right created, or if it has been created in a different moment.
  • The method I suggest depends from a system function that in some systems could not be present, or that could be less reliable.
  • With the modern CPUs, which are a way faster than the CPUs used 10 years ago, there could be the problem to use the right value for the threshold value to decide when an object has been freshly created, or not.

The other solution would be to use an object property that is set to a a value from the object creator, and that is set to a different value from all the methods of the object.
In this case the problem would be to forget to add the code to change that property in each method.

Once again I would ask to myself "Is there a really need to do this?".

As a possible partial solution if you only wanted one of an object to be consumed by a method maybe you could look at a Singleton. In this way the method in question could not create another instance if it existed already.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!