1 //------------------------------------------------------------------------------
2 // <copyright file="MemberRelationshipService.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
6 namespace System.ComponentModel.Design.Serialization {
7 using System.Collections.Generic;
8 using System.Diagnostics.CodeAnalysis;
9 using System.Security.Permissions;
12 /// A member relationship service is used by a serializer to announce that one
13 /// property is related to a property on another object. Consider a code
14 /// based serialization scheme where code is of the following form:
16 /// object1.Property1 = object2.Property2
18 /// Upon interpretation of this code, Property1 on object1 will be
19 /// set to the return value of object2.Property2. But the relationship
20 /// between these two objects is lost. Serialization schemes that
21 /// wish to maintain this relationship may install a MemberRelationshipService
22 /// into the serialization manager. When an object is deserialized
23 /// this serivce will be notified of these relationships. It is up to the service
24 /// to act on these notifications if it wishes. During serialization, the
25 /// service is also consulted. If a relationship exists the same
26 /// relationship is maintained by the serializer.
28 [HostProtection(SharedState = true)]
29 public abstract class MemberRelationshipService
31 private Dictionary<RelationshipEntry,RelationshipEntry> _relationships = new Dictionary<RelationshipEntry,RelationshipEntry>();
34 /// Returns the the current relationship associated with the source, or MemberRelationship.Empty if
35 /// there is no relationship. Also sets a relationship between two objects. Empty
36 /// can also be passed as the property value, in which case the relationship will
39 [SuppressMessage("Microsoft.Design", "CA1043:UseIntegralOrStringArgumentForIndexers")]
40 public MemberRelationship this[MemberRelationship source] {
42 if (source.Owner == null) throw new ArgumentNullException("Owner");
43 if (source.Member== null) throw new ArgumentNullException("Member");
45 return GetRelationship(source);
48 if (source.Owner == null) throw new ArgumentNullException("Owner");
49 if (source.Member == null) throw new ArgumentNullException("Member");
51 SetRelationship(source, value);
56 /// Returns the the current relationship associated with the source, or null if
57 /// there is no relationship. Also sets a relationship between two objects. Null
58 /// can be passed as the property value, in which case the relationship will
61 [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1023:IndexersShouldNotBeMultidimensional")]
62 public MemberRelationship this[object sourceOwner, MemberDescriptor sourceMember] {
64 if (sourceOwner == null) throw new ArgumentNullException("sourceOwner");
65 if (sourceMember == null) throw new ArgumentNullException("sourceMember");
67 return GetRelationship(new MemberRelationship(sourceOwner, sourceMember));
70 if (sourceOwner == null) throw new ArgumentNullException("sourceOwner");
71 if (sourceMember == null) throw new ArgumentNullException("sourceMember");
73 SetRelationship(new MemberRelationship(sourceOwner, sourceMember), value);
78 /// This is the implementation API for returning relationships. The default implementation stores the
79 /// relationship in a table. Relationships are stored weakly, so they do not keep an object alive.
81 protected virtual MemberRelationship GetRelationship(MemberRelationship source) {
82 RelationshipEntry retVal;
84 if (_relationships != null && _relationships.TryGetValue(new RelationshipEntry(source), out retVal) && retVal.Owner.IsAlive) {
85 return new MemberRelationship(retVal.Owner.Target, retVal.Member);
88 return MemberRelationship.Empty;
92 /// This is the implementation API for returning relationships. The default implementation stores the
93 /// relationship in a table. Relationships are stored weakly, so they do not keep an object alive. Empty can be
94 /// passed in for relationship to remove the relationship.
96 protected virtual void SetRelationship(MemberRelationship source, MemberRelationship relationship) {
98 if (!relationship.IsEmpty && !SupportsRelationship(source, relationship)) {
99 string sourceName = TypeDescriptor.GetComponentName(source.Owner);
100 string relName = TypeDescriptor.GetComponentName(relationship.Owner);
101 if (sourceName == null) {
102 sourceName = source.Owner.ToString();
104 if (relName == null) {
105 relName = relationship.Owner.ToString();
107 throw new ArgumentException(SR.GetString(SR.MemberRelationshipService_RelationshipNotSupported, sourceName, source.Member.Name, relName, relationship.Member.Name));
110 if (_relationships == null) {
111 _relationships = new Dictionary<RelationshipEntry,RelationshipEntry>();
114 _relationships[new RelationshipEntry(source)] = new RelationshipEntry(relationship);
118 /// Returns true if the provided relatinoship is supported.
120 public abstract bool SupportsRelationship(MemberRelationship source, MemberRelationship relationship);
123 /// Used as storage in our relationship table
125 private struct RelationshipEntry {
126 internal WeakReference Owner;
127 internal MemberDescriptor Member;
128 private int hashCode;
130 internal RelationshipEntry(MemberRelationship rel) {
131 Owner = new WeakReference(rel.Owner);
133 hashCode = rel.Owner == null ? 0 : rel.Owner.GetHashCode();
137 public override bool Equals(object o) {
138 if (o is RelationshipEntry) {
139 RelationshipEntry e = (RelationshipEntry)o;
146 public static bool operator==(RelationshipEntry re1, RelationshipEntry re2){
147 object owner1 = (re1.Owner.IsAlive ? re1.Owner.Target : null);
148 object owner2 = (re2.Owner.IsAlive ? re2.Owner.Target : null);
149 return owner1 == owner2 && re1.Member.Equals(re2.Member);
152 public static bool operator!=(RelationshipEntry re1, RelationshipEntry re2){
153 return !(re1 == re2);
156 public override int GetHashCode() {
163 /// This class represents a single relationship between an object and a member.
165 public struct MemberRelationship {
166 private object _owner;
167 private MemberDescriptor _member;
169 public static readonly MemberRelationship Empty = new MemberRelationship();
172 /// Creates a new member relationship.
174 public MemberRelationship(object owner, MemberDescriptor member) {
175 if (owner == null) throw new ArgumentNullException("owner");
176 if (member == null) throw new ArgumentNullException("member");
183 /// Returns true if this relationship is empty.
185 public bool IsEmpty {
187 return _owner == null;
192 /// The member in this relationship.
194 public MemberDescriptor Member {
201 /// The object owning the member.
203 public object Owner {
210 /// Infrastructure support to make this a first class struct
212 public override bool Equals(object obj) {
213 if (!(obj is MemberRelationship))
216 MemberRelationship rel = (MemberRelationship)obj;
217 return rel.Owner == Owner && rel.Member == Member;
221 /// Infrastructure support to make this a first class struct
223 public override int GetHashCode() {
224 if (_owner == null) return base.GetHashCode();
225 return _owner.GetHashCode() ^ _member.GetHashCode();
228 /// Infrastructure support to make this a first class struct
230 public static bool operator ==(MemberRelationship left, MemberRelationship right) {
231 return left.Owner == right.Owner && left.Member == right.Member;
235 /// Infrastructure support to make this a first class struct
237 public static bool operator !=(MemberRelationship left, MemberRelationship right) {
238 return !(left == right);