XamlMember.IsReadOnly returns false if there is private get accessor.
This is used to filter nonpublic accessors out, so replaced its usage with
!IsWritePublic to check truly read-only members.
This fix also required some changes in markup types (as IsReadOnly value now
differs).
{
public ArrayExtension ()
{
- Items = new ArrayList ();
+ items = new ArrayList ();
}
public ArrayExtension (Array elements)
if (elements == null)
throw new ArgumentNullException ("elements");
Type = elements.GetType ().GetElementType ();
- Items = new ArrayList (elements);
+ items = new ArrayList (elements);
}
public ArrayExtension (Type arrayType)
if (arrayType == null)
throw new ArgumentNullException ("arrayType");
Type = arrayType;
- Items = new ArrayList ();
+ items = new ArrayList ();
}
[ConstructorArgument ("arrayType")]
public Type Type { get; set; }
+ IList items;
[DesignerSerializationVisibility (DesignerSerializationVisibility.Content)]
- public IList Items { get; private set; }
+ public IList Items {
+ get { return items; }
+ }
public void AddChild (Object value)
{
{
public PropertyDefinition ()
{
- Attributes = new List<Attribute> ();
+ attributes = new List<Attribute> ();
}
- public IList<Attribute> Attributes { get; private set; }
+ List<Attribute> attributes;
+ public IList<Attribute> Attributes {
+ get { return attributes; }
+ }
[DefaultValue ("public")]
public string Modifier { get; set; }
throw new ArgumentNullException ("type");
if (definition == null)
throw new ArgumentNullException ("definition");
+ if (type == definition)
+ return true;
foreach (var iface in type.GetInterfaces ())
if (iface == definition || (iface.IsGenericType && iface.GetGenericTypeDefinition () == definition))
public static IEnumerable<XamlMember> GetSortedConstructorArguments (this XamlType type)
{
var args = type.GetConstructorArguments ().ToArray ();
- var ci = type.UnderlyingType.GetConstructors ().FirstOrDefault (c => c.GetParameters ().Length == args.Length);
- if (ci == null)
- return null;
- var pis = ci.GetParameters ();
- return args.OrderBy (c => pis.FindParameterWithName (c.ConstructorArgumentName ()).Position);
+ foreach (var ci in type.UnderlyingType.GetConstructors ().Where (c => c.GetParameters ().Length == args.Length)) {
+ var pis = ci.GetParameters ();
+ if (args.Length != pis.Length)
+ continue;
+ bool mismatch = false;
+ foreach (var pi in pis)
+ for (int i = 0; i < args.Length; i++)
+ if (!args.Any (a => a.ConstructorArgumentName () == pi.Name))
+ mismatch = true;
+ if (mismatch)
+ continue;
+ return args.OrderBy (c => pis.FindParameterWithName (c.ConstructorArgumentName ()).Position);
+ }
+ return null;
}
static ParameterInfo FindParameterWithName (this IEnumerable<ParameterInfo> pis, string name)
{
- var ret = pis.FirstOrDefault (pi => pi.Name == name);
- if (ret == null)
- throw new ArgumentException (String.Format ("Constructor argument '{0}' is expected, but was not found.", name));
- return ret;
+ return pis.FirstOrDefault (pi => pi.Name == name);
}
public static string ConstructorArgumentName (this XamlMember xm)
underlying_member = propertyInfo;
DeclaringType = schemaContext.GetXamlType (propertyInfo.DeclaringType);
target_type = DeclaringType;
- UnderlyingGetter = propertyInfo.GetGetMethod ();
- UnderlyingSetter = propertyInfo.GetSetMethod ();
+ UnderlyingGetter = propertyInfo.GetGetMethod (true);
+ UnderlyingSetter = propertyInfo.GetSetMethod (true);
}
public XamlMember (string attachableEventName, MethodInfo adder, XamlSchemaContext schemaContext)
}
// collection items: return GetObject and Items.
- if (xm != null && xm.Type.IsCollection && xm.IsReadOnly) {
+ if (xm != null && xm.Type.IsCollection && !xm.IsWritePublic) {
yield return new XamlNodeInfo (XamlNodeType.GetObject, xobj);
// Write Items member only when there are items (i.e. do not write it if it is empty).
var xnm = new XamlNodeMember (xobj, XamlLanguage.Items);
continue;
// Other collections as well, but needs different iteration (as nodes contain GetObject and EndObject).
- if (xce.Current.Member.IsReadOnly && xce.Current.Member.Type != null && xce.Current.Member.Type.IsCollection) {
+ if (!xce.Current.Member.IsWritePublic && xce.Current.Member.Type != null && xce.Current.Member.Type.IsCollection) {
var e = GetNodes (xce.Current.Member, xce.Current.Value).GetEnumerator ();
if (!(e.MoveNext () && e.MoveNext () && e.MoveNext ())) // GetObject, EndObject and more
continue;
public XamlMember GetMember (string name)
{
- return LookupMember (name, false);
+ return LookupMember (name, true);
}
public IList<XamlType> GetPositionalParameters (int parameterCount)
foreach (var ei in UnderlyingType.GetEvents (bf))
yield return new XamlMember (ei, SchemaContext);
}
+
+ static bool IsPublicAccessor (MethodInfo mi)
+ {
+ return mi != null && mi.IsPublic;
+ }
- static bool IsCollectionType (Type type)
+ bool IsCollectionType (Type type)
{
if (type == null)
return false;
- if (type.IsArray)
- return true;
-
- Type [] ifaces = type.GetInterfaces ();
- foreach (Type i in ifaces)
- if (i.IsGenericType && i.GetGenericTypeDefinition ().Equals (typeof (ICollection<>)))
- return true;
- foreach (Type i in ifaces)
- if (i == typeof (IList))
- return true;
-
- foreach (var iface in type.GetInterfaces ())
- if (iface == typeof (IDictionary) || (iface.IsGenericType && iface.GetGenericTypeDefinition () == typeof (IDictionary<,>)))
- return true;
-
- return false;
+ var xt = SchemaContext.GetXamlType (type);
+ return xt.LookupCollectionKind () != XamlCollectionKind.None;
}
protected virtual IList<XamlType> LookupAllowedContentTypes ()
if (type.ImplementsAnyInterfacesOf (typeof (IDictionary), typeof (IDictionary<,>)))
return XamlCollectionKind.Dictionary;
- if (type.ImplementsAnyInterfacesOf (typeof (ICollection), typeof (ICollection<>)))
+ if (type.ImplementsAnyInterfacesOf (typeof (IList), typeof (ICollection<>)))
return XamlCollectionKind.Collection;
return XamlCollectionKind.None;
{
public MyArrayExtension ()
{
- Items = new ArrayList ();
+ items = new ArrayList ();
}
public MyArrayExtension (Array array)
{
- this.Items = array;
+ items = new ArrayList (array);
this.Type = array.GetType ().GetElementType ();
}
[ConstructorArgument ("type")]
public Type Type { get; set; }
- public IList Items { get; private set; }
+ IList items;
+ public IList Items {
+ get { return items; }
+ private set { items = value; }
+ }
public override object ProvideValue (IServiceProvider serviceProvider)
{
Assert.IsFalse (t.IsArray, "#1.1");
Assert.IsFalse (t.IsCollection, "#1.2");
Assert.IsNull (t.ItemType, "#1.3");
+
t = new XamlType (typeof (ArrayList), sctx);
Assert.IsFalse (t.IsArray, "#2.1");
Assert.IsTrue (t.IsCollection, "#2.2");
Assert.IsNotNull (t.ItemType, "#2.3");
Assert.AreEqual ("Object", t.ItemType.Name, "#2.4");
+
t = new XamlType (typeof (int []), sctx);
Assert.IsTrue (t.IsArray, "#3.1");
- // why?
Assert.IsFalse (t.IsCollection, "#3.2");
Assert.IsNotNull (t.ItemType, "#3.3");
Assert.AreEqual (typeof (int), t.ItemType.UnderlyingType, "#3.4");
+
+ t = new XamlType (typeof (IList), sctx);
+ Assert.IsFalse (t.IsArray, "#4.1");
+ Assert.IsTrue (t.IsCollection, "#4.2");
+ Assert.IsNotNull (t.ItemType, "#4.3");
+ Assert.AreEqual (typeof (object), t.ItemType.UnderlyingType, "#4.4");
+
+ t = new XamlType (typeof (ICollection), sctx); // it is not a XAML collection.
+ Assert.IsFalse (t.IsArray, "#5.1");
+ Assert.IsFalse (t.IsCollection, "#5.2");
+ Assert.IsNull (t.ItemType, "#5.3");
+
+ t = new XamlType (typeof (ArrayExtension), sctx);
+ Assert.IsFalse (t.IsArray, "#6.1");
+ Assert.IsFalse (t.IsCollection, "#6.2");
+ Assert.IsNull (t.ItemType, "#6.3");
}
[Test]
public void CustomArrayExtension ()
{
var xt = new XamlType (typeof (MyArrayExtension), sctx);
+ var xm = xt.GetMember ("Items");
+ Assert.IsNotNull (xt.GetAllMembers ().FirstOrDefault (m => m.Name == "Items"), "#0");
+ Assert.IsNotNull (xm, "#1");
+ Assert.IsFalse (xm.IsReadOnly, "#2"); // Surprisingly it is False. Looks like XAML ReadOnly is true only if it lacks set accessor. Having private member does not make it ReadOnly.
+ Assert.IsTrue (xm.Type.IsCollection, "#3");
+ Assert.IsFalse (xm.Type.IsConstructible, "#4");
}
}