Serialize to XML an object that contains IList - c#

So I have an Object called FormType.
It contains some strings, booleans etc.
But FormType also contains this:
private IList<FormTypeVersion> _versions = new List<FormTypeVersion>();
public virtual IList<FormTypeVersion> Versions
{
get { return _versions; }
set { _versions = value; }
}
Is this why I am getting this error:
{"Cannot serialize member 'Domain.FormType.Versions' of type 'System.Collections.Generic.IList`1
Also - FormTypeVersion also contains some ILists.
How can I get round this error, it happens at this line:
var xm = new XmlSerializer(typeof(T));

The XmlSerializer cannot deserialize interfaces (unless you want to implement IXmlSerializable yourself on the FormType object). That is why you are seeing that exception.
If you change your IList to List it should work like in the following example:
[Serializable]
public class FormType
{
private List<FormTypeVersion> _versions = new List<FormTypeVersion>();
public virtual List<FormTypeVersion> Versions
{
get { return _versions; }
set { _versions = value; }
}
}
If you don't have the luxury to change your type from IList to List, then the cleanest approach is to implement IXmlSerializable. There are other solutions using abstract types, reflection and similar, but i wouldn't call that clean.

Related

Serialize nested Interface properties without any boilerplate code [duplicate]

I would like to XML serialize an object that has (among other) a property of type IModelObject (which is an interface).
public class Example
{
public IModelObject Model { get; set; }
}
When I try to serialize an object of this class, I receive the following error:
"Cannot serialize member Example.Model of type Example because it is an interface."
I understand that the problem is that an interface cannot be serialized. However, the concrete Model object type is unknown until runtime.
Replacing the IModelObject interface with an abstract or concrete type and use inheritance with XMLInclude is possible, but seems like an ugly workaround.
Any suggestions?
This is simply an inherent limitation of declarative serialization where type information is not embedded within the output.
On trying to convert <Flibble Foo="10" /> back into
public class Flibble { public object Foo { get; set; } }
How does the serializer know whether it should be an int, a string, a double (or something else)...
To make this work you have several options but if you truly don't know till runtime the easiest way to do this is likely to be using the XmlAttributeOverrides.
Sadly this will only work with base classes, not interfaces. The best you can do there is to ignore the property which isn't sufficient for your needs.
If you really must stay with interfaces you have three real options:
Hide it and deal with it in another property
Ugly, unpleasant boiler plate and much repetition but most consumers of the class will not have to deal with the problem:
[XmlIgnore()]
public object Foo { get; set; }
[XmlElement("Foo")]
[EditorVisibile(EditorVisibility.Advanced)]
public string FooSerialized
{
get { /* code here to convert any type in Foo to string */ }
set { /* code to parse out serialized value and make Foo an instance of the proper type*/ }
}
This is likely to become a maintenance nightmare...
Implement IXmlSerializable
Similar to the first option in that you take full control of things but
Pros
You don't have nasty 'fake' properties hanging around.
you can interact directly with the xml structure adding flexibility/versioning
Cons
you may end up having to re-implement the wheel for all the other properties on the class
Issues of duplication of effort are similar to the first.
Modify your property to use a wrapping type
public sealed class XmlAnything<T> : IXmlSerializable
{
public XmlAnything() {}
public XmlAnything(T t) { this.Value = t;}
public T Value {get; set;}
public void WriteXml (XmlWriter writer)
{
if (Value == null)
{
writer.WriteAttributeString("type", "null");
return;
}
Type type = this.Value.GetType();
XmlSerializer serializer = new XmlSerializer(type);
writer.WriteAttributeString("type", type.AssemblyQualifiedName);
serializer.Serialize(writer, this.Value);
}
public void ReadXml(XmlReader reader)
{
if(!reader.HasAttributes)
throw new FormatException("expected a type attribute!");
string type = reader.GetAttribute("type");
reader.Read(); // consume the value
if (type == "null")
return;// leave T at default value
XmlSerializer serializer = new XmlSerializer(Type.GetType(type));
this.Value = (T)serializer.Deserialize(reader);
reader.ReadEndElement();
}
public XmlSchema GetSchema() { return(null); }
}
Using this would involve something like (in project P):
public namespace P
{
public interface IFoo {}
public class RealFoo : IFoo { public int X; }
public class OtherFoo : IFoo { public double X; }
public class Flibble
{
public XmlAnything<IFoo> Foo;
}
public static void Main(string[] args)
{
var x = new Flibble();
x.Foo = new XmlAnything<IFoo>(new RealFoo());
var s = new XmlSerializer(typeof(Flibble));
var sw = new StringWriter();
s.Serialize(sw, x);
Console.WriteLine(sw);
}
}
which gives you:
<?xml version="1.0" encoding="utf-16"?>
<MainClass
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Foo type="P.RealFoo, P, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null">
<RealFoo>
<X>0</X>
</RealFoo>
</Foo>
</MainClass>
This is obviously more cumbersome for users of the class though avoids much boiler plate.
A happy medium may be merging the XmlAnything idea into the 'backing' property of the first technique. In this way most of the grunt work is done for you but consumers of the class suffer no impact beyond confusion with introspection.
The solution to this is using reflection with the DataContractSerializer. You don't even have to mark your class with [DataContract] or [DataMember]. It will serialize any object, regardless of whether it has interface type properties (including dictionaries) into xml. Here is a simple extension method that will serialize any object into XML even if it has interfaces (note you could tweak this to run recursively as well).
public static XElement ToXML(this object o)
{
Type t = o.GetType();
Type[] extraTypes = t.GetProperties()
.Where(p => p.PropertyType.IsInterface)
.Select(p => p.GetValue(o, null).GetType())
.ToArray();
DataContractSerializer serializer = new DataContractSerializer(t, extraTypes);
StringWriter sw = new StringWriter();
XmlTextWriter xw = new XmlTextWriter(sw);
serializer.WriteObject(xw, o);
return XElement.Parse(sw.ToString());
}
what the LINQ expression does is it enumerates each property,
returns each property that is an interface,
gets the value of that property (the underlying object),
gets the type of that concrete object
puts it into an array, and adds that to the serializer's list of known types.
Now the serializer knows how about the types it is serializing so it can do its job.
If you know your interface implementors up-front there's a fairly simple hack you can use to get your interface type to serialize without writing any parsing code:
public interface IInterface {}
public class KnownImplementor01 : IInterface {}
public class KnownImplementor02 : IInterface {}
public class KnownImplementor03 : IInterface {}
public class ToSerialize {
[XmlIgnore]
public IInterface InterfaceProperty { get; set; }
[XmlArray("interface")]
[XmlArrayItem("ofTypeKnownImplementor01", typeof(KnownImplementor01))]
[XmlArrayItem("ofTypeKnownImplementor02", typeof(KnownImplementor02))]
[XmlArrayItem("ofTypeKnownImplementor03", typeof(KnownImplementor03))]
public object[] InterfacePropertySerialization {
get { return new[] { InterfaceProperty }; ; }
set { InterfaceProperty = (IInterface)value.Single(); }
}
}
The resulting xml should look something along the lines of
<interface><ofTypeKnownImplementor01><!-- etc... -->
You can use ExtendedXmlSerializer. This serializer support serialization of interface property without any tricks.
var serializer = new ConfigurationContainer().UseOptimizedNamespaces().Create();
var obj = new Example
{
Model = new Model { Name = "name" }
};
var xml = serializer.Serialize(obj);
Your xml will look like:
<?xml version="1.0" encoding="utf-8"?>
<Example xmlns:exs="https://extendedxmlserializer.github.io/v2" xmlns="clr-namespace:ExtendedXmlSerializer.Samples.Simple;assembly=ExtendedXmlSerializer.Samples">
<Model exs:type="Model">
<Name>name</Name>
</Model>
</Example>
ExtendedXmlSerializer support .net 4.5 and .net Core.
Replacing the IModelObject interface with an abstract or concrete type and use inheritance with XMLInclude is possible, but seems like an ugly workaround.
If it is possible to use an abstract base I would recommend that route. It will still be cleaner than using hand-rolled serialization. The only trouble I see with the abstract base is that your still going to need the concrete type? At least that is how I've used it in the past, something like:
public abstract class IHaveSomething
{
public abstract string Something { get; set; }
}
public class MySomething : IHaveSomething
{
string _sometext;
public override string Something
{ get { return _sometext; } set { _sometext = value; } }
}
[XmlRoot("abc")]
public class seriaized
{
[XmlElement("item", typeof(MySomething))]
public IHaveSomething data;
}
Unfortunately there's no simple answer, as the serializer doesn't know what to serialize for an interface. I found a more complete explaination on how to workaround this on MSDN
Unfortuantely for me, I had a case where the class to be serialized had properties that had interfaces as properties as well, so I needed to recursively process each property. Also, some of the interface properties were marked as [XmlIgnore], so I wanted to skip over those. I took ideas that I found on this thread and added some things to it to make it recursive. Only the deserialization code is shown here:
void main()
{
var serializer = GetDataContractSerializer<MyObjectWithCascadingInterfaces>();
using (FileStream stream = new FileStream(xmlPath, FileMode.Open))
{
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(stream, new XmlDictionaryReaderQuotas());
var obj = (MyObjectWithCascadingInterfaces)serializer.ReadObject(reader);
// your code here
}
}
DataContractSerializer GetDataContractSerializer<T>() where T : new()
{
Type[] types = GetTypesForInterfaces<T>();
// Filter out duplicates
Type[] result = types.ToList().Distinct().ToList().ToArray();
var obj = new T();
return new DataContractSerializer(obj.GetType(), types);
}
Type[] GetTypesForInterfaces<T>() where T : new()
{
return GetTypesForInterfaces(typeof(T));
}
Type[] GetTypesForInterfaces(Type T)
{
Type[] result = new Type[0];
var obj = Activator.CreateInstance(T);
// get the type for all interface properties that are not marked as "XmlIgnore"
Type[] types = T.GetProperties()
.Where(p => p.PropertyType.IsInterface &&
!p.GetCustomAttributes(typeof(System.Xml.Serialization.XmlIgnoreAttribute), false).Any())
.Select(p => p.GetValue(obj, null).GetType())
.ToArray();
result = result.ToList().Concat(types.ToList()).ToArray();
// do the same for each of the types identified
foreach (Type t in types)
{
Type[] embeddedTypes = GetTypesForInterfaces(t);
result = result.ToList().Concat(embeddedTypes.ToList()).ToArray();
}
return result;
}
I have found a simpler solution (you don't need the DataContractSerializer), thanks to this blog here:
XML serializing derived types when base type is in another namespace or DLL
But 2 problems can rise in this implementation:
(1) What if DerivedBase is not in the namespace of class Base, or even worse in a project that depends on Base namespace, so Base cannot XMLInclude DerivedBase
(2) What if we only have class Base as a dll ,so again Base cannot XMLInclude DerivedBase
Till now, ...
So the solution to the 2 problems is by using XmlSerializer Constructor (Type, array[]) :
XmlSerializer ser = new XmlSerializer(typeof(A), new Type[]{ typeof(DerivedBase)});
A detailed example is provided here on MSDN:
XmlSerializer Constructor (Type, extraTypesArray[])
It seems to me that for DataContracts or Soap XMLs, you need to check the XmlRoot as mentioned here in this SO question.
A similar answer is here on SO but it isn't marked as one, as it not the OP seems to have considered it already.
in my project, I have a
List<IFormatStyle> FormatStyleTemplates;
containing different Types.
I then use the solution 'XmlAnything' from above, to serialize this list of different types.
The generated xml is beautiful.
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[XmlArray("FormatStyleTemplates")]
[XmlArrayItem("FormatStyle")]
public XmlAnything<IFormatStyle>[] FormatStyleTemplatesXML
{
get
{
return FormatStyleTemplates.Select(t => new XmlAnything<IFormatStyle>(t)).ToArray();
}
set
{
// read the values back into some new object or whatever
m_FormatStyleTemplates = new FormatStyleProvider(null, true);
value.ForEach(t => m_FormatStyleTemplates.Add(t.Value));
}
}

Looking for a more elegant way to perform custom get/set functionality on class properties

I'm trying to find a way to refine some code that I have. I work with a 3rd party API that has a REALLY complicated API request object (I'll call it ScrewyAPIObject) that has tons of repetition in it. Every time you want to set a particular property, it can take a page worth of code. So I built a library to provide a simplified wrapper around the setting/getting of its properties (and to handle some value preprocessing).
Here's a stripped-down view of how it works:
public abstract class LessScrewyWrapper
{
protected ScrewyAPIRequest _screwy = new ScrewyAPIRequest();
public void Set(string value)
{
Set(_getPropertyName(), value);
}
public void Set(string property, string value)
{
// Preprocess value and set the appropriate property on _screwy. This part
// has tons of code, but we'll just say it looks like this:
_screwy.Fields[property] = "[" + value + "]";
}
protected string _getPropertyName()
{
// This method looks at the Environment.StackTrace, finds the correct set_ or
// get_ method call and extracts the property name and returns it.
}
public string Get()
{
// Get the property name being access
string property = _getPropertyName();
// Search _screwy's structure for the value and return it. Again, tons of code,
// so let's just say it looks like this:
return _screwy.Fields[property];
}
public ScrewyAPIRequest GetRequest()
{
return _screwy;
}
}
Then I have a child class that represents one specific type of the screwy API request (there are multiple kinds that all have the same structure but different setups). Let's just say this one has two string properties, PropertyA and PropertyB:
public class SpecificScrewyAPIRequest : LessScrewyWrapper
{
public string PropertyA
{
get { return Get(); }
set { Set(value); }
}
public string PropertyB
{
get { return Get(); }
set { Set(value); }
}
}
Now when I want to go use this library, I can just do:
SpecificScrewyAPIRequest foo = new SpecificScrewyAPIRequest();
foo.PropertyA = "Hello";
foo.PropertyB = "World";
ScrewyAPIRequest request = foo.GetRequest();
This works fine and dandy, but there are different kinds of data types, which involves using generics in my Set/Get methods, and it just makes the child classes look a little kludgy when you're dealing with 50 properties and 50 copies of Get() and Set() calls.
What I'd LIKE to do is simply define fields, like this:
public class SpecificScrewyAPIRequest : LessScrewyWrapper
{
public string PropertyA;
public string PropertyB;
}
It would make the classes look a LOT cleaner. The problem is that I don't know of a way to have .NET make a callback to my custom handlers whenever the values of the fields are accessed and modified.
I've seen someone do something like this in PHP using the __set and __get magic methods (albeit in a way they were not intended to be used), but I haven't found anything similar in C#. Any ideas?
EDIT: I've considered using an indexed approach to my class with an object-type value that is cast to its appropriate type afterwards, but I'd prefer to retain the approach where the property is defined with a specific type.
Maybe in your case DynamicObject is a suitable choice:
public class ScrewyDynamicWrapper : DynamicObject
{
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// get your actual value based on the property name
Console.WriteLine("Get Property: {0}", binder.Name);
result = null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// set your actual value based on the property name
Console.WriteLine("Set Property: {0} # Value: {2}", binder.Name, value);
return true;
}
}
And define your wrapper objects:
public class ScrewyWrapper
{
protected dynamic ActualWrapper = new ScrewyDynamicWrapper();
public int? PropertyA
{
get { return ActualWrapper.PropertyA; }
set { ActualWrapper.PropertyA = value; }
}
public string PropertyB
{
get { return ActualWrapper.PropertyB; }
set { ActualWrapper.PropertyB = value; }
}
}
However, you can't rely on the property type inside ScrewyDynamicWrapper with this approach, so it depends on your actual API requirements - maybe it won't work for you.
Instead of fields, If you define as property in class, It will be more easy.
public class SpecificScrewyAPIRequest
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
}
Then you can create extension generic method to return ScrewyAPIRequest object.
public static class Extensions
{
public static ScrewyAPIRequest GetRequest<T>(this T obj)
{
ScrewyAPIRequest _screwy = new ScrewyAPIRequest();
var test= obj.GetType().GetProperties();
foreach (var prop in obj.GetType().GetProperties())
{
_screwy.Fields[prop.Name] = prop.GetValue(obj, null);
}
return _screwy;
}
}
Now you can easily get ScrewyAPIRequest from any class object.
Your code will look like following.
SpecificScrewyAPIRequest foo = new SpecificScrewyAPIRequest();
foo.PropertyA = "Hello";
foo.PropertyB = "World";
ScrewyAPIRequest request = foo.GetRequest();

How to cast an custom object to List<object>

I have a parent class, with has a property that contain a list of the children class.
//Parent Class :
public class Family
{
private MemberList _familymember = new MemberList();
public MemberList FamilyMember
{
get { return _familymember ; }
set { _familymember = value; }
}
}
//Children Class :
public class Member
{
private string _name;
public string Name
{
get { return _name; }
set { _name= value; }
}
}
public class MemberList : List<Member>
{
}
//And here is how I use them :
Family myFamily = new Family();
Member dad = new Member();
Member mom = new Member();
//I add the children into the parent property :
myFamily.FamilyMember.Add(dad);
myFamily.FamilyMember.Add(mom);
//I have other different similar parent-children classes, eg : School-Classroom, Country-States and etc.
//In one condition, I need to write a generic class to process the List<custom> type property :
//some function that will return a children list object.
object ChildrenList = somefunction();
List<object> ObjectList = (List<object>)ChildrenList;
//and trying to get the Type name inside the List :
Type ChildrenType = ObjectList.GetType().GetGenericArguments()[0];
//It gives me error :
Unable to cast object of type 'MemberList' to type'System.Collections.Generic.List`1[System.Object]'
//or when I process other types of list
Unable to cast object of type 'ClassroomList' to type 'System.Collections.Generic.List`1[System.Object]'
Unable to cast object of type 'StateList' to type 'System.Collections.Generic.List`1[System.Object]'
I am trying to write a general class to process the list, therefore I wouldn't know the type of the list property. Any idea how I can cast them into List ?
All help is appreciated !!
Update & Solution :
Like aevitas suggested, I have changed the list property to use
private List<Member> _familymember = List<Member>();
And then I use the IList interface I found in other topic,
object returnedList = somefunction(); // some function that return a List of object.
IList myList = (IList)returnedList ;
Now the rest of the code works, I can loop through the IList like normal.
Thanks all!
You could add a common interface for all children classes (Member, Classroom & State), otherwise there is absolutely no connection between List<object> and List<MemberType> as this would allow the following:
List<object> myList = (List<object>) memberTypeList;
myList.Add(5); // oops
Also: as unfortunate as it is, there is no type aliasing in C# like there is in C or C++. Still, deriving from a class looks like its a workaround but its semantically wrong and should not be used.
You should never inherit List<T>, instead you should declare one instead:
public class Family
{
private List<Member> _familymember = List<Member>();
public List<Member> FamilyMember
{
get { return _familymember ; }
set { _familymember = value; }
}
}
On top of that, you should never be casting your types down to object, use a common type or interface instead as D.R. suggested.
If you want to stick to your guns, and you want to convert your MemberList object to a List<Member>, you could do it like this:
public static IEnumerable<T> GetList<T>(List<T> source)
{
return source;
}
And call it like this:
var list = GetList<Member>(memberList).ToList();
That should at least solve your compiler errors, but it won't solve the design errors in this one.

Providing a Read Only List of Classes in C#

I have a set of custom data types that can be used to manipulate basic blocks of data. For example:
MyTypeA Foo = new MyTypeA();
Foo.ParseString(InputString);
if (Foo.Value > 4) return;
Some of these types define read-only properties that describe aspects of the types (for example a name, bit size, etc.).
In my custom framework I want to be able to provide these types to the user for use in their applications but I also want to give the user a list of the available types which they could easily bind to a combobox. My current approach:
public static class DataTypes
{
static ReadOnlyCollection<MyDataType> AvailableTypes;
static DataTypes()
{
List<MyDataType> Types = new List<MyDataType>();
Types.Add(new MyTypeA());
Types.Add(new MyTypeB());
AvailableTypes = new ReadOnlyCollection<MyDataType>(Types);
}
}
What concerns me about this is that the user might obtain a type from the AvailableTypes list (by selecting a combobox item for example) and then use that reference directly rather than creating a clone of the type and using their own reference.
How can I make the list of available types read only so that it doesn't allow any writing or changes to the type instances, forcing the user to create their own clone?
Alternatively is there a better way of providing a list of available types?
Thanks, Andy
Make your custom Type class immutable, same as System.Type and you dont have to worry. A end user can fetch all the data it wants but he can not modify the object in any way.
EDIT: Example of immutable class
Take the following class for instance:
public class ImmutablePerson
{
private readonly string name; //readonly ensures the field can only be set in the object's constructor(s).
private readonly int age;
public ImmutablePerson(string name, int age)
{
this.name = name;
this.age = age;
}
public int Age { get { return this.age; } } //no setter
public string Name { get { return this.name; } }
public ImmutablePerson GrowUp(int years)
{
return new ImmutablePerson(this.name, this.age + years); //does not modify object state, it returns a new object with the new state.
}
}
ImmutablePerson is an immutable class. Once created there is no way a consumer can modify it in any way. Notice that the GrowUp(int years) method does not modify the state of the object at all, it just returns a new instance of ImmutablePerson with the new values.
I hope this helps you understand immutable objects a little better and how they can help you in your particular case.
To get around the problems you've mentioned, you could create a wrapper around your instances, and have the wrapper provide the functionality you require.
For example:
public class TypeDescriptor
{
private MyDataType _dataType;
public TypeDescriptor(MyDataType dataType)
{
_dataType = dataType;
}
public override string ToString()
{
return _dataType.ToString();
}
}
You class would then look something like:
public static class DataTypes
{
public static ReadOnlyCollection<TypeDescriptor> AvailableTypes;
static DataTypes()
{
List<TypeDescriptor> Types = new List<TypeDescriptor>();
Types.Add(new TypeDescriptor(new MyTypeA()));
Types.Add(new TypeDescriptor(new MyTypeB()));
AvailableTypes = new ReadOnlyCollection<TypeDescriptor>(Types);
}
}
Binding to the list and relying on the ToString() will now result in your data types ToString being called.
Create a list of types rather than a list of instances. e.g.
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB()));
etc.
To answer the comment on binding to a drop down list:
MyDropDown.Datasource = Type.Select(t => t.Name);
MyDropDown.DataBind();
This will not use the custom property of your classes but it will give you the simple calss name without all the other guff e.g. MyTypeA
A collection cannot "inject" type modifiers into its members. The collection you have declared is readonly. If you want MyDataType to be readonly you must declare that way.
Somthing like :
EDIT extended class to have a parse method
public class MyDataType
{
private MyDataType()
{
...
}
internal static MyDataType Parse(string someString)
{
MyDataType newOne = new MyDataType();
newOne.Value = ... //int.Parse(someString); ?
}
public int Value { get; private set; }
}
If the collection stays generic there is no readonly constraint.
You would use it like this, following your example.
MyTypeA foo = MyTypeA.Parse(inputString);
if (foo.Value > 4) return;
You probably shouldn't store instances of your types in the list. Instead you can store types. These can be used to create instances:
public static class DataTypes
{
static ReadOnlyCollection<Type> AvailableTypes;
static DataTypes()
{
List<Type> Types = new List<Type>();
Types.Add(typeof(MyTypeA));
Types.Add(typeof(MyTypeB));
AvailableTypes = new ReadOnlyCollection<MyDataType>(Type);
}
}
You can use Activator.CreateInstance to create a concrete instance:
Object myType = Activator.CreateInstance(AvailableTypes[0]);
Unless your types share a common base type you cannot downcast the result and an Object isn't that useful.
Also the use of the term type in your code makes my example a bit confusing as I suggest you store the types of something called type.
You could consider creating and attribute that you then can apply to MyTypeA, MyTypeB etc. Then you can build the AvailableTypes using reflection and the list will always be up to date with your code. E.g. if you add MyTypeC and use the attribute it will automatically be added to the list.
You can also add a display string property to the attribute and use that for display in the combo box. If you want to do that you should store a small object combining the type and the display string in AvailableTypes.
Here is an example. Using generic words like type and data can be confusing so to pick a random name I just use foo. Obviously you should use a more descriptive name.
[AttributeUsage(AttributeTargets.Class, Inherited = false)]
sealed class FooAttribute : Attribute {
public FooAttribute(String displayName) {
DisplayName = displayName;
}
public String DisplayName { get; private set; }
}
You can decorate you classes using this attribute:
[Foo("Type A")]
class MyTypeA { ... }
[Foo("Type B")]
class MyTypeB { ... }
For the combobox you want a list of factory objects with a nice ToString implementation (this class can be improved by adding some error handling which I have left out to save space):
class FooFactory {
readonly Type type;
public FooFactory(Type type) {
this.type = type;
DisplayName = ((FooAttribute) Attribute.GetCustomAttribute(
type,
typeof(FooAttribute))
).DisplayName;
}
public String DisplayName { get; private set; }
public Object CreateFoo() {
return Activator.CreateInstance(this.type);
}
public override String ToString() {
return DisplayName;
}
}
Returning Object from CreateFoo isn't very useful but that is a separate issue.
You can build this list at run-time:
var factories = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => Attribute.IsDefined(t, typeof(FooAttribute)))
.Select(t => new FooFactory(t));
I'm not exactly sure of what you want but should something like this be ok ?
public static class DataTypes
{
static Dictionary<string,Type> AvailableTypes
= new Dictionary<string,Type>()
{
{ "MyTypeA", MyTypeA },
{ "MyTypeB", MyTypeB },
...
};
}
That is actually return types instead of sample instances of theses types. Thus you would be sure that only new instances would be created by the user of your class.
Then in the calling code :
MyTypeA a = Activator.CreateInstance(DataTypes.AvailableTypes["MyTypeA"]);

Can I apply an attribute to an inherited member?

Suppose I have the following (trivially simple) base class:
public class Simple
{
public string Value { get; set; }
}
I now want to do the following:
public class PathValue : Simple
{
[XmlAttribute("path")]
public string Value { get; set; }
}
public class ObjectValue : Simple
{
[XmlAttribute("object")]
public string Value { get; set; }
}
But without actually redefining the property. I want to apply attributes to members of the base class. Is this possible?
The real problem is that in my serialization mechanism from/to XML (which works brilliantly btw), I find a lot of similar elements where only the names of the attributes differ (they're not consistent, and I don't control the format). Right now I need to create a different class for every such element, whereas they're like 100% the same (apart from the attributes).
I don't think it's possible, but you might never know.
UPDATE:
I tried Marc's approach, but to no avail:
public class Document
{
public PathValue Path;
public ObjectValue Object;
}
class Program
{
static void Main(string[] args)
{
var doc = new Document()
{
Path = new PathValue() { Value = "some path" },
Object = new ObjectValue() { Value = "some object" }
};
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(PathValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("path") });
overrides.Add(typeof(ObjectValue), "Value", new XmlAttributes() { XmlAttribute = new XmlAttributeAttribute("object") });
XmlSerializer serializer = new XmlSerializer(typeof(Document), overrides);
serializer.Serialize(Console.Out, doc);
Console.WriteLine();
Console.ReadLine();
}
}
...doesn't do the trick.
I'm going to answer this question myself, so that I can accept this answer. I don't like the answer, but I suppose it's the only valid answer.
The answer is: No, you can't do it.
Could you perhaps use the overload XmlSerializer constructor that lets you pass in the attributes to apply at runtime? Then you don't have to worry about it...
caveat: you want to cache the serializer instance and re-use it; otherwise (with the complex constructors) it does dynamic type generation each time.
Example:
using System;
using System.Xml.Serialization;
public class Simple {
public string Value { get; set; }
static void Main() {
XmlAttributeOverrides overrides = new XmlAttributeOverrides();
overrides.Add(typeof(Simple), "Value", new XmlAttributes {
XmlAttribute = new XmlAttributeAttribute("path")
});
XmlSerializer pathSerializer = new XmlSerializer(
typeof(Simple), overrides);
// cache and re-use pathSerializer!!!
Simple obj = new Simple();
obj.Value = "abc";
pathSerializer.Serialize(Console.Out, obj);
}
}
Output:
<Simple xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" path="abc" />
How about this:
public class Simple
{
[XmlIgnore]
public string Value { get; set; }
}
public class PathValue : Simple
{
[XmlAttribute("path")]
public string Path {
get { return base.Value != null ? base.Value : null; }
set { base.Value = value != null ? value : null; }
}
}
public class ObjectValue : Simple
{
[XmlAttribute("object")]
public string Object {
get { return base.Value != null ? base.Value : null; }
set { base.Value = value != null ? value : null; }
}
}
This is the same technique used to serialize an unserializable type like a Uri that takes a serializable type in the constructor.
You are probably aware of this, but as an idea (although the code structure would completely change in that case):
One way would be to serialize the base class as a collection of name-value pairs, using custom serialization (there is also XDocument and similar helpful stuff to make it easier). Although it doesn't enforce type safety, it would spare you from doing lots of manual work.
I also prefer going for custom serialization because it allows a wider range of possibilities (serializing immutable classes, for example). XmlSerializer is also really nasty sometimes (e.g. I hate adding the "MyFieldSpecified" property to create optional attributes).
Perhaps you can mark the base class property with a common mapping, than you only override the property in inherited classes where it should be different. At least you would save some overriding.

Categories

Resources