append extra fields to existing objects
-
In our project, I needed the
XmlReader
to carry an object-bound List. Unfortunately this class is abstract and I didn't really want to implement to whole thing just with that extra field. So I usedTypeDescriptor
to add an additionalAttribute
to the XmlReader:XsdErrorListAttribute listAttrib = new XsdErrorListAttribute();
XmlReader xreader = ...;
TypeDescriptor.AddAttributes(xreader, listAttrib);The XsdErrorListAttribute was quite simple:
class XsdErrorListAttribute : Attribute
{
internal XsdErrorListAttribute()
{
ErrorList = new List<XsdError>();
}internal List<XsdError> ErrorList { get; set; } internal static XsdErrorListAttribute getFromObject(object o) { var result = from Attribute a in TypeDescriptor.GetAttributes(o) where a.GetType() == typeof(XsdErrorListAttribute) select a; if (result.Count() == 1) return (XsdErrorListAttribute)result.Single(); else return null; } }
The static method tried to extract the attribute from an object. At the position where the list should be retrieved simply:
XsdErrorListAttribute attrib = XsdErrorListAttribute.getFromObject(tmp); attrib.Liste.Add(new XsdError(...)); //yes, assuming that it's != null ...
You can even add attributes to whole classes, or just like this to give your objects an extra piece of information.
-
In our project, I needed the
XmlReader
to carry an object-bound List. Unfortunately this class is abstract and I didn't really want to implement to whole thing just with that extra field. So I usedTypeDescriptor
to add an additionalAttribute
to the XmlReader:XsdErrorListAttribute listAttrib = new XsdErrorListAttribute();
XmlReader xreader = ...;
TypeDescriptor.AddAttributes(xreader, listAttrib);The XsdErrorListAttribute was quite simple:
class XsdErrorListAttribute : Attribute
{
internal XsdErrorListAttribute()
{
ErrorList = new List<XsdError>();
}internal List<XsdError> ErrorList { get; set; } internal static XsdErrorListAttribute getFromObject(object o) { var result = from Attribute a in TypeDescriptor.GetAttributes(o) where a.GetType() == typeof(XsdErrorListAttribute) select a; if (result.Count() == 1) return (XsdErrorListAttribute)result.Single(); else return null; } }
The static method tried to extract the attribute from an object. At the position where the list should be retrieved simply:
XsdErrorListAttribute attrib = XsdErrorListAttribute.getFromObject(tmp); attrib.Liste.Add(new XsdError(...)); //yes, assuming that it's != null ...
You can even add attributes to whole classes, or just like this to give your objects an extra piece of information.
Neat idea! You're paying a performance price though. How about generating a class that extends XmlReader but implements by wrapping an existing implementation? I believe one could build a small code-generating tool that would do so without a lot of work, and it neatly solves the problem here because the framework does provide implementations but only the abstract base type is public. Something like this:
// This class is *generated* by your little tool.
public class WrappedXmlReader : XmlReader
{
XmlReader implementation;public WrappedXmlReader(XmlReader implementation) { this.implementation = implementation; } #region "Implement" abstract XmlReader members by delegation public override int AttributeCount { get { return implementation.AttributeCount; } } // ... public void Close() { implementation.Close(); } // ... #endregion
}
// Now you extend the wrapped reader as you now have a non-sealed concrete "implementation" to derive from.
public class MyReader : WrappedXmlReader
{
public MyReader(Stream s): base(XmlReader.Create(s)) {}public MyReader(XmlReader r) : base(r) {} public string Foo { get; set; } public void Bar() { Debug.WriteLine("Hello world"); }
}
-
Neat idea! You're paying a performance price though. How about generating a class that extends XmlReader but implements by wrapping an existing implementation? I believe one could build a small code-generating tool that would do so without a lot of work, and it neatly solves the problem here because the framework does provide implementations but only the abstract base type is public. Something like this:
// This class is *generated* by your little tool.
public class WrappedXmlReader : XmlReader
{
XmlReader implementation;public WrappedXmlReader(XmlReader implementation) { this.implementation = implementation; } #region "Implement" abstract XmlReader members by delegation public override int AttributeCount { get { return implementation.AttributeCount; } } // ... public void Close() { implementation.Close(); } // ... #endregion
}
// Now you extend the wrapped reader as you now have a non-sealed concrete "implementation" to derive from.
public class MyReader : WrappedXmlReader
{
public MyReader(Stream s): base(XmlReader.Create(s)) {}public MyReader(XmlReader r) : base(r) {} public string Foo { get; set; } public void Bar() { Debug.WriteLine("Hello world"); }
}
ah ok thats really good! i had the problem inheritating the XmlReader because i couldnt fill the abstract methods. a code generator is always a good idea. but well, we call the TypeDescriptor very less than 1%, sometimes only once per action (more than a million calls to the reader). like this, all the indirect function calls cost more. so it depends on usage which method to use.
-
In our project, I needed the
XmlReader
to carry an object-bound List. Unfortunately this class is abstract and I didn't really want to implement to whole thing just with that extra field. So I usedTypeDescriptor
to add an additionalAttribute
to the XmlReader:XsdErrorListAttribute listAttrib = new XsdErrorListAttribute();
XmlReader xreader = ...;
TypeDescriptor.AddAttributes(xreader, listAttrib);The XsdErrorListAttribute was quite simple:
class XsdErrorListAttribute : Attribute
{
internal XsdErrorListAttribute()
{
ErrorList = new List<XsdError>();
}internal List<XsdError> ErrorList { get; set; } internal static XsdErrorListAttribute getFromObject(object o) { var result = from Attribute a in TypeDescriptor.GetAttributes(o) where a.GetType() == typeof(XsdErrorListAttribute) select a; if (result.Count() == 1) return (XsdErrorListAttribute)result.Single(); else return null; } }
The static method tried to extract the attribute from an object. At the position where the list should be retrieved simply:
XsdErrorListAttribute attrib = XsdErrorListAttribute.getFromObject(tmp); attrib.Liste.Add(new XsdError(...)); //yes, assuming that it's != null ...
You can even add attributes to whole classes, or just like this to give your objects an extra piece of information.
-
You could simplify the usage of this with some Extension methods. Regards, Mark Hurd, B.Sc.(Ma.) (Hons.)
well, no ;) a extension method in fact is only something like a static method:
void doSomething(this String str, int i) { /*...*/ }
String s;
s.doSomething(5);becomes
static void doSomething(String str, int i) { /*...*/ }
String s;
doSomething(s, 5);you can not access private or protected fields, and especially you can not append an extra field to an object.
-
In our project, I needed the
XmlReader
to carry an object-bound List. Unfortunately this class is abstract and I didn't really want to implement to whole thing just with that extra field. So I usedTypeDescriptor
to add an additionalAttribute
to the XmlReader:XsdErrorListAttribute listAttrib = new XsdErrorListAttribute();
XmlReader xreader = ...;
TypeDescriptor.AddAttributes(xreader, listAttrib);The XsdErrorListAttribute was quite simple:
class XsdErrorListAttribute : Attribute
{
internal XsdErrorListAttribute()
{
ErrorList = new List<XsdError>();
}internal List<XsdError> ErrorList { get; set; } internal static XsdErrorListAttribute getFromObject(object o) { var result = from Attribute a in TypeDescriptor.GetAttributes(o) where a.GetType() == typeof(XsdErrorListAttribute) select a; if (result.Count() == 1) return (XsdErrorListAttribute)result.Single(); else return null; } }
The static method tried to extract the attribute from an object. At the position where the list should be retrieved simply:
XsdErrorListAttribute attrib = XsdErrorListAttribute.getFromObject(tmp); attrib.Liste.Add(new XsdError(...)); //yes, assuming that it's != null ...
You can even add attributes to whole classes, or just like this to give your objects an extra piece of information.
internal static XsdErrorListAttribute getFromObject(object o) {
return TypeDescriptor.GetAttributes(o).OfType<XsdErrorListAttribute>().FirstOrDefault();
}does the same, or am i wrong?