3

I'm writing a small library where I'm writing some interfaces that takes a MailMessage object and returns a class back to me with a single send method that abstracts away how that MailMessage will be sent. I have control over the class that will do the actual sending, but I don't have control over the implementing strategy classes. I'd like to prevent any implementing strategy classes from altering the MailMessage. How can I make the MailMessage (and the collections it contains) immutable or create a clone of it? I don't see a .Clone method on MailMessage itself like I do on other classes. Will I have to result to new'ing up a new MailMessage object and doing a property-by-property set on that new MailMessage?

Note, I'm mostly a Java guy and am helping a client with C# 2.0 code, so I'm slightly unfamiliar with C# / .NET idioms for things like this. Any help is appreciated.

whaley
  • 16,075
  • 10
  • 57
  • 68

2 Answers2

2

I don't think there is a quick solution for this. The MailMessage is inheritly mutable and isn't designed to be cloned or serialized/deserialized. If you need to make sure nobody can change it, don't cache it, but define a class that holds a copy of the values of the message and make new MailMessage instances out of this instance.

Steven
  • 166,672
  • 24
  • 332
  • 435
1

I know this is an old question, but I recently had to implement this so here's what I did. This is a shallow clone, though with a little more work it could be made into a deep clone.

        private MailMessage MailMessageShallowCopy(MailMessage original)
    {
        string to = original.To.ToString();
        string from = original.From.ToString();
        string subject = original.Subject;
        string body = original.Body;
        string cc = original.CC.ToString();
        string bcc = original.Bcc.ToString();

        MailMessage clone = new MailMessage(from, to, subject, body);
        if (!string.IsNullOrEmpty(cc))
        {
            clone.CC.Add(cc);
        }
        if (!string.IsNullOrEmpty(bcc))
        {
            clone.Bcc.Add(bcc);
        }
        foreach (AlternateView view in original.AlternateViews)
        {
            var clonedView = new AlternateView(view.ContentStream);
            foreach (var resource in view.LinkedResources)
            {
                clonedView.LinkedResources.Add(resource);
            }
            clone.AlternateViews.Add(clonedView);
        }
        foreach (Attachment attachment in original.Attachments)
        {
            clone.Attachments.Add(attachment);
        }
        clone.BodyEncoding = original.BodyEncoding;
        clone.DeliveryNotificationOptions = original.DeliveryNotificationOptions;
        foreach (NameValueCollection header in original.Headers)
        {
            clone.Headers.Add(header);
        }
        clone.HeadersEncoding = original.HeadersEncoding;
        clone.IsBodyHtml = original.IsBodyHtml;
        clone.Priority = original.Priority;
        foreach (MailAddress mailAddress in original.ReplyToList)
        {
            clone.ReplyToList.Add(mailAddress);
        }
        clone.Sender = original.Sender;
        clone.SubjectEncoding = original.SubjectEncoding;
        return clone;
    }
Andrew Hagner
  • 804
  • 1
  • 9
  • 18
  • This is not shallow clone code. This is actually deep clone code. – dnk.nitro Jan 05 '15 at 20:25
  • 1
    @dnk.nitro Why? All contents of the internal collections are copied by reference. – M. Mimpen Nov 09 '16 at 13:48
  • Well, I agree that internal collections are copied by reference, but new collections are instantiated, so I would rather call it a hybrid clone :) – dnk.nitro Jan 16 '19 at 21:05
  • @SamanGhadirian - your edit looks substantial enough that you should probably add a different answer. – dbc Oct 09 '21 at 02:13