0
MemberwiseClone(Object fromObject, Object toObject)

This is a function I would have wanted to use several times in my life. It has a massive advantage over the current implementation of MemberwiseClone as it does not create any garbage.

Let's say for example you have an array of 1000 objects, and you want to iterate through and test what effect calling SomeFunction() has on the object without corrupting the original. A fairly common occurrence in the world of scientific simulations.

If you use the existing implementation of MemberwiseClone, you're creating 1000 objects worth of garbage. If my suggested method existed, you could create 1 object and reuse that for all iterations. This obviously creates far less garbage and far less work for the GC. I can't imagine the implementation of the method would differ that much from the original, so I'm guessing it would have taken almost no time to add to the framework.

While it's perfectly possible to maintain a GetCopy() method for an object that copies field by field there are two problems with this. First and foremost, it has to be maintained. Whenever a new field is added, if you forget to add it to the GetCopy, your program is broken. Secondly, for large object it's much less efficient than copying a memory block for a clone.

I've had to resort to embedding structs within my objects to store all fields, then I don't need to remember to add them to the GetCopy method, and I can copy them all with a single assignment. The problem with this is that it makes the code really ugly.

So, is there a good reason this method was never implemented? Or is it just not as useful as I'm imagining.

Will Calderwood
  • 4,393
  • 3
  • 39
  • 64
  • 3
    The .NET designers just didn't add methods that have such a high chance for being used incorrectly. – Hans Passant Aug 09 '13 at 11:27
  • 3
    _[..] all features are unimplemented until someone designs, implements, tests, documents and ships the feature [..]_ - Eric Lippert – default Aug 09 '13 at 11:30
  • @HansPassant Please can you explain why there would be a high chance of it being used incorrectly? – Will Calderwood Aug 09 '13 at 11:31
  • 1
    @Default That goes without saying. I was asking if there was a reason why that hasn't happened, for what to me seems like a very useful method. – Will Calderwood Aug 09 '13 at 11:32
  • To be frank, I've never had the use for this method. To expand on my previous comment, even though it might seem to "take almost no time to add" there is still a lot of other work that has to be done before adding a feature. – default Aug 09 '13 at 11:32
  • 1
    Just multiply the low odds of a shallow copy being correct by the odds that the objects are the exact same type and you'll end up with a *very* low number. – Hans Passant Aug 09 '13 at 11:35
  • @HansPassant If the odds of a shallow copy being correct are so low then why does the current implementation of MemberwiseClone exist? And I assume it's possible to check if the objects are the exact same type in the implementation - or is that not possible with the way the existing implementation of MemberwiseClone works? – Will Calderwood Aug 09 '13 at 11:39
  • 1
    That's kinda obvious, sometimes you do want a shallow copy. It is the multiplication that hurts. This is a very non-constructive way to deal with whatever problem you are trying to solve btw. – Hans Passant Aug 09 '13 at 11:47
  • @HansPassant I've solved my problem - this method would have made the solution a lot easier and the code a lot more readable. This is a Q&A site, not a problem solving site, so I was asking a Q. Thanks for your responses. – Will Calderwood Aug 09 '13 at 11:52
  • 3
    Ultimately, the answer to "is there a reason this method doesn't exist" is yes, there is a reason. No one implemented it. *Why* they didn't implement it, you would have to ask them. We can only guess and offer opinions. –  Aug 09 '13 at 13:46
  • 2
    IMO, it is a question. – ValidfroM Aug 09 '13 at 14:44
  • 2
    @Amy All anyone can ever do is offer opinions. Opinions are what I'm asking for. Yes, if you want to be pedantic, there's a 'reason' for everything, so I've changed the question to ask for a 'good reason' instead. – Will Calderwood Aug 09 '13 at 15:23
  • @Will: Most questions on SO are based on facts, not opinions. I'm not being pedantic, but you are being argumentative and defensive. You told HansPassant what this site is; I think he has a better idea what SO is than any of us do. I'm voting to close. "Many good questions generate some degree of opinion based on expert experience, but answers to this question will tend to be almost entirely based on opinions, rather than facts, references, or specific expertise." –  Aug 09 '13 at 15:34
  • 2
    I don't know, I think the question is perfectly acceptable—it's just about the design of a language/API. I don't see why there's anything wrong with that. Sure, there is some opinion involved, but there's opinion involved in everything. The answers to this would indeed be "based on expert experience" and "specific expertise", just like the close reason says we want. And I think what Hans posted here in a couple of comments is the answer. I'll probably not find many people who agree with me, but I'm voting to reopen anyway. – Cody Gray - on strike Aug 10 '13 at 06:13
  • Implement it by yourself: public static object CustomMemberwiseClone(object source) { var clone = FormatterServices.GetUninitializedObject(source.GetType()); for (var type = source.GetType(); type != null; type = type.BaseType) { var fields = type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly); foreach (var field in fields) field.SetValue(clone, field.GetValue(source)); } return clone; } – CleanCoder Dec 15 '20 at 15:58

2 Answers2

3

So, is there a reason this method was never implemented? Or is it just not as useful as I'm imagining.

Only your class is guaranteed to know whether MemberwiseClone is a valid method to use or not. Should the values referred to by private fields be unique to one instance or not? Do some fields relate to the lifetime of an instance? Are there readonly fields which must be set by a constructor? It makes sense that MemberwiseClone should only be called inside a class implementation.

Let's say for example you have an array of 1000 objects, and you want to iterate through and test what effect calling SomeFunction() has on the object without corrupting the original. A fairly common occurrence in the world of science.

  • If you are writing tests, they should already be self-contained.

  • If you want a new array based on some transformation, the transformation function should be the one returning a new object, not mutating the original.

EDIT

I understand you want to copy fields to an existing object instead of creating another clone instance to avoid the overhead of instantiation (I'm not sure instantiation is really any significant overhead though).

The problem is that other objects could be referring to your first clone and have no way of knowing that it's a "new" clone when you revert it again. It doesn't make sense for such a method to be called "clone" because a true clone is a new object.

For revert functionality, it still makes more sense for it to be internal to a class, for the same reasons that MemberwiseClone is. A generic function that takes an arbitrary clone and applies all fields to another arbitrary object makes too many assumptions. The object itself should be responsible for cloning itself when it's initialized, and reverting the appropriate fields.

nmclean
  • 7,564
  • 2
  • 28
  • 37
  • I'm running repeated simulations on objects. As you would expect, the simulations change the object, then I need to revert it back to the original for each simulation. The easiest way to do this is to keep the original copy, and duplicate it for each simulation. As you could expect, this is CPU intensive, and I don't want the overhead of excess garbage. – Will Calderwood Aug 09 '13 at 15:09
  • I think you're probably overestimating how much "excess garbage" there is in creating new objects. Construction is fast, and the garbage collector will clean up the old objects. I edited my answer with more. – nmclean Aug 09 '13 at 16:14
  • This is the question that made me wonder about this. The speed increases I achieved would suggest there are huge inefficiencies in creating large objects as opposed to cloning onto an existing object. http://stackoverflow.com/questions/18086950/memberwiseclone-equivalent-to-an-existing-object/ – Will Calderwood Aug 09 '13 at 16:21
  • I'm sorry I cannot get deeper into the subject, but I'll just thow in two questions of doubt at different levels: (1:usage/consumption/existence) why didn't you write your own MemberwiseClone? it's a few lines per class, you can even generate it with some script, and you can make perfectly sure that your impl will not make any excess copies. (2:request/idea/design) "MemberwiseClone": please try to define, what is a "member"? Is a public property a member? and public Field? private property? private field? What if **I/he/she** understand the 'member' differently? – quetzalcoatl Aug 10 '13 at 10:45
  • I'll leave the (1) upto you and your judgement, but as for (2), please see [this topic](http://stackoverflow.com/questions/536349/why-no-icloneablet) and then [this article at MSDN](http://blogs.msdn.com/b/brada/archive/2004/05/03/125427.aspx). While ICloneable is not strictly deprecated, it is considered 'a bad thing', especially in public APIs, as it almost always introduces a real confusion. – quetzalcoatl Aug 10 '13 at 10:51
0

That feature would be useful, but the answer to question like "Why does x not exist although it is obviously useful?" is most of the time:

[..] all features are unimplemented until someone designs, implements, tests, documents and ships the feature [..] - Eric Lippert

Thanks to user "Default" for quoting this in the comments. It means that features cost money so we don't get to have all of them.

IN any case there is no fundamental reason why this feature cannot exist or is horribly broken by design. It would work.

usr
  • 168,620
  • 35
  • 240
  • 369