I have a class with over 100 uniquely named properties and more than 20 child-classes, sometimes in lists. Below is a greatly simplified illustration of what I mean:
public class classA
{
public String PropertyA1 { get; set; }
public int PropertyA2{get;set;}
public List<classB> myList;
public classC myClass { get; set; }
public void SetProperty(String PropertyName)
{
// Match property name to property in this class or child class.
}
}
class classB
{
public String PropertyB1 { get; set; }
public bool PropertyB2 { get; set; }
}
class classC
{
public String PropertyC1 { get; set; }
}
I would like to do two things that may or may not be possible. The first thing I need to do is iterate through every public property, including those of child classes and classes in a list, and translate the values. I know I can accomplish the parsing by serializing to xml and parsing through the results. I even have the code in place to convert to xml, as the function of the class is to build an xml object. However, I am worried that parsing through the xml might be much more expensive than accessing the properties through reflection. Can reflection be used in this manner, and would it be quicker than modifying the xml?
The other thing I would like to do is access any property passing the property name into a method. I realize I would need a separate method for accessing classes within lists, and may have to convert the list to a dictionary. The question is, would this be possible, and would the code only need to be in the parent class, or would each of the child classes need to repeat the code?
Method that will set the property with the given name:
public void SetProperty(String propertyName, object value)
{
this.GetType().GetProperty(propertyName).SetValue(this, value);
}
A few things about the implementation:
The type used is the dynamic actual type of the object, that will find members that are in derived classes (as long as the object is of the derived type of course).
The property info has no idea of what object it came from, so this must be passed in again to the SetValue() call.
The second part of your question, to iterate through a list of properties, can be solved by using GetProperties() to get all the properties of the object, including inherited ones:
var properties = this.GetType().GetProperties();
Related
I have an object that I store in the session, something like this:
[Serializable]
public class GoyaAppUserServerSession
{
public int TheInt{ get; set; }
public string TheString{ get; set; }
public byte TheByte{ get; set; }
public void SomeMethod() { ... }
public void SomeOtherMethod() { ... }
}
My server session has 3 values and 2 methods. When the object is serialized and deserialized, does the serialization only apply to the values, in which case it's negligible, or is the code that's inside the methods also serialized as a string?
Thanks.
Only the values; since methods are a compiled definition of the class, there is no reason to store these; therefore it only stores the values of the properties. Depending on what you are serializing with, it usually uses the properties as the names of the fields during the serialization process. For instance, if you use XML, it would use the property name as attribute or element, and the value as the inner content.
Given the following classes/interfaces defined in a base library:
public interface IWorkContext {
T Node<T>() where T : class, IHierachy<T>;
IHierachyItem Node();
}
public interface IHierachyItem {
int Id { get; set; }
string Title { get; set; }
}
public interface IHierachy<T> : IHierachyItem where T : IHierachy<T> {
T Parent { get; set; }
IList<T> Children { get; set; }
}
public class WorkContext {
public static IWorkContext Current {
get { return DependencyResolver.Current.GetService<IWorkContext>(); }
}
}
Which has the following implentation inside another library (that references the base library above):
public class DefaultWorkContext : IWorkContext {
// Nhibernate session
private readonly ISession _session;
public DefaultWorkContext(ISession session) {
_session = session;
}
public T Node<T>() where T : class, IHierachy<T> {
return _session.Get<T>(2);
}
public IHierachyItem Node() {
return Node<SiteMapNode>();
}
}
Where SiteMapNode exists in the same library (and is mapped to a database table):
public class SiteMapNode : IHierachy<SiteMapNode> {
public virtual int Id { get; set; }
public virtual SiteMapNode Parent { get; set; }
public virtual string Title { get; set; }
public virtual IList<SiteMapNode> Children { get; set; }
public SiteMapNode() {
Children = new List<SiteMapNode>();
}
}
I can say the following to access a node and get the parent:
var node = WorkContext.Current.Node();
var parentNode = ((IHierachy<SiteMapNode>)node).Parent;
var node2 = WorkContext.Current.Node<SiteMapNode>();
var parentNode2 = node2.Parent;
However i don't like either approach as option 1 requires a case and option 2 requires me to pass a default type.
Is it possible to refactor this sample so that i can access the Parent and Child the same way I get the Id and Title.
I hope i've explained the problem clear enough. I'd appreciate the help. Thanks
Your problem might be more clear if you used explicit types instead of var. Declaring a variable with var does not make the variable type dynamic, it just makes the compiler figure out what specific type the variable needs to be (and it can be dangerous because you don't know as clearly what type it determines).
So, having declared variables with a specific type (whether you know what that type is or not), you can then only access what that declared type knows unless you cast it appropriately.
I think in the end there is no way to accomplish exactly what you want without specifying a type at some point as a type argument (in angle-brackets) or an explicit cast. You apparently want to convert a non-specific iherited/implementing type to a handy specific type, but that requires telling the complier a specific type for it to become.
But you may get closer to what you'd like by changing your approach. What if you used a non-generic IHierarchy? (also correct the spelling) If...
public inetrface IHierarchy : IHierarchyItem
{
IHierarchy Parent { get; set; }
IList<IHierarchy> Children { get; set; }
}
...then any IHierarchy node variable could access node.Parent and node.Children... and also node.Id and node.Title because the IHierarchyItem is required and thus is known to IHierarchy.
This approach would handle the hierarchy aspects easily and allows polymorphism in your WorkContext.Current (etc) return values, but it would require explicit casting from there to access anything specific to a class outside of the defined members of IHierarchy. It's not clear how much of an issue that might be for your purpose.
You could also perhaps layer a generic IHierarchy<T> : IHierarchy on top of it to allow handling by a specific type without further casting. You might have to define one or both interface members explicitly rather than implicitly (in implementing classes) to avoid name collisions on the properties without generic type arguments.
EDITED TO ADD:
For example, something like:
public interface IHierarchy<T> : IHierarchy // Implies IHierarchyItem
where T : IHierarchy<T>
{ ... } // As you had it.
Then in your implementation class:
public SiteMapNode : IHierarchy<SiteMapNode> // Implies IHierarchy
{
private SiteMapNode _Parent;
private IList<SiteMapNode> _Children;
// Implicit implement of IHierarchyItem and members of SiteMapNode itself.
int Id { get; set; }
string Title { get; set; }
// Implicit implementation of IHierarchy<SiteMapNode> members
// These are also members of SiteMapNode itself.
SiteMapNode Parent
{
get { return _Parent; }
set { _Parent = value; }
}
IList<SiteMapNode> Children
{
get return _Children;
set _Children = value;
}
// Explicit implementation of IHierarchy members
// The interface prefix is required to distinguish these from the
// type-specific members above to declare different return types.
IHierarchy IHierarchy.Parent
{
get { return _Parent; } // Might need (IHierarchy) cast
set { Parent = (SiteMapNode)value; }
}
IList<IHierarchy> IHierarchy.Children
{
get { return _Children; } // Might need (IList<IHierarchy>) cast
set { _Children = (IList<SiteMapNode>)value; }
}
}
(Or get fancier and have more sanity-checking in the IHierarchy implementations.) I might have missed some other explicit casting needed also; I'm not positive that the lists can be cast directly in this way, but I think by having IHierarchy<T> inherit IHierarchy it ensures that SiteMapNode is a valid IHierarchy and thus the elements of the list work for both list types). If that list casting doesn't work, you may have to create a custom generic collection class to manage the children as both unspecified IHierarchy and as generic IHierarchy<T>.
For performance reasons you may want to add IHierarchy _CastParent; and IList<IHierarchy> _CastChildren; members and save the unspecified IHierarchy casts of these objects to avoid having to repeatedly recast them. I suggest that you always cast to the specific types (when setting from the unspecified) but you might defer casting from the specific types to the unspecified references until they are actually needed.
Now, all that, of course, is only if this extra complexity is actually helpful for what you need. It would allow you to handle the hierarchy objects as unspecified types (which might be cast more specific later, or never) or as specific or generic hierarchy types which would preserve their type knowledge for handling without casting. You would still need to cast to a specific type at some point to convert from an unspecified IHierarchy return type if you wanted to then handle them as the type-specific hierarchy.
I am working on an application which currently creates data entity objects from the results of a sql query. In the database 3 of the tables are very similar but have several different properties.
My initial plan was to create 3 different classes, even though each class is very similar. However when I came to create the method which returns a list of objects, I have hit a stumbling block as the return type will be different depending on which mode the application is in.
e.g.
public class A
{
public int Id {get;}
public string Name {get;}
}
public class B
{
public int Id {get;}
public string Name {get;}
public string ExtraInfo {get;}
}
public class MainScreen
{
...
this.resultsGrid.DataSource = LoadData();
}
I would prefer not to write one method to load a list of each data type.
What should the return type of LoadData() be, to allow it to be generic as possible.
What is the most elegant way of dealing with this scenario?
Thanks,
Sean
You should have inheritance to allow polymorphism, so you would have a base class that all entities included in the data binding derive from it.
Then, you can have a mid-base class to have some shared properties like Name and ID.
Base class:
public abstract class Entity
{
}
Entity with Name and ID:
public class NameAndIDEntity : Entity
{
public int Id { get; set; }
public string Name { get; set; }
}
Entity with Name, ID and ExtraInfo:
public class NameIDAndExtraEntity : NameAndIDEntity
{
public string ExtraInfo { get; set; }
}
Entity with other information (can't be derived from NameAndIDEntity), derives from Entity so it can be included in the data binding:
public class OtherInformationEntity : Entity
{
public int Age { get; set; }
}
Finally, you can make the LoadData return type Entity.
Simples!
Create a class ListItem (with properties Id and Name, I presume). In your factory class/method, make instances of that class from the records into a List and bind the datasource to the list.
Don't be scared to create specialised classes for your UI.
UPDATE: Forgot to mention. Avoid inheritance as much as possible.
First you can create an inheitance tree in your project, where base class holds a shared/common properties among set of dfferent types
Second you can retrieve from the query anonymous type and after map it to a known type by mapping them to a real type, like from Jon Skeet's blog Horrible grotty hack: returning an anonymous type instance
That means that you need by the way know which query what type returns (can not avoid that), but this can reduce amount of fraction you need to add to your code, like from example:
static class GrottyHacks
{
internal static T Cast<T>(object target, T example) //CAST TO SPECIFIED TYPE
{
return (T) target;
}
}
class CheesecakeFactory
{
static object CreateCheesecake()
{
return new { Fruit="Strawberry", Topping="Chocolate" };
}
static void Main()
{
object weaklyTyped = CreateCheesecake(); //ANONYMOUS TYPE GENERATION
var stronglyTyped = GrottyHacks.Cast(weaklyTyped,
new { Fruit="", Topping="" }); //"MAPPING"
Console.WriteLine("Cheesecake: {0} ({1})",
stronglyTyped.Fruit, stronglyTyped.Topping);
}
}
I have a class (more complex, but simplified for the example) like this:
public class MyClass {
public MyClass() { }
[XmlAttribute("somename")]
public String MyString { get; set; }
[XmlElement("AString")]
public List<String> TheList { get; set; }
// Other uninteresting methods and private members.
}
Xml Serialization works fine. What I'd like to do (if it isn't too crazy) is change this class to use generics so that I can have "TheList" use different types. What I want is for the XmlElement name to be able to be specified per instance (or per type) somehow.
Ideal would be something where the name is set when the instance is created. It would be nice to macro replace the attribute parameter strings on creation, but I have no idea if anything similar is possible. Maybe it would look something like:
public class MyClass<T, (MagicalMacro)> {
// Some kind of constructor, methods, whatever as needed.
// MyString as above.
[XmlElement(MagicalMacro)] // This does not compile.
public List<T> TheList { get; set; }
// Etc.
}
...
MyClass<int, (MagicalMacro)> myClass = new MyClass<int, "AnInteger">();
Less ideal but still satisfactory would be to name the "TheList" output name based on the type of T.
public class MyClass<T> {
// Same constructor and MyString as the first example.
[XmlElement(typeof(T).Name)] // This does not compile - string not constant.
public List<T> TheList { get; set; }
// Etc.
}
Thanks.
Attributes need literals. The way to approach this is by using XmlAttributeOverrides to configure it at runtime, and pass that to the XmlSerializer constructor. However: cache and re-use the serializer instances when you do this, or you will leak dynamically generated assemblies.
This might be a simple one, but my head is refusing to wrap around that, so an outside view is always useful in that case!
I need to design an object hierarchy to implement a Parameter Registration for a patient. This will take place on a certain date and collect a number of different parameters about a patient (bloodpressure, heartrate etc). The values of those Parameter Registrations can be of different types, such as strings, integers, floats or even guids (for lookup lists).
So we have:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public class ParameterRegistrationValue
{
public Parameter Parameter { get; set; }
public RegistrationValue RegistrationValue { get; set; } // this needs to accomodate the different possible types of registrations!
}
public class Parameter
{
// some general information about Parameters
}
public class RegistrationValue<T>
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
UPDATE: Thanks to the suggestions, the model has now morphed to the following:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public IList<ParameterRegistrationValue> ParameterRegistrationValues { get; set; }
}
public abstract class ParameterRegistrationValue()
{
public static ParameterRegistrationValue CreateParameterRegistrationValue(ParameterType type)
{
switch(type)
{
case ParameterType.Integer:
return new ParameterRegistrationValue<Int32>();
case ParameterType.String:
return new ParameterRegistrationValue<String>();
case ParameterType.Guid:
return new ParameterRegistrationValue<Guid>();
default: throw new ArgumentOutOfRangeException("Invalid ParameterType: " + type);
}
}
public Parameter Parameter { get; set; }
}
public class ParameterRegistrationValue<T> : ParameterRegistrationValue
{
public T RegistrationValue {get; set; }
}
public enum ParameterType
{
Integer,
Guid,
String
}
public class Parameter
{
public string ParameterName { get; set; }
public ParameterType ParameterType { get; set;}
}
which is indeed a bit simpler, but now I'm wondering, since the IList in ParameterRegistration points to the abstract ParameterRegistrationValue object, how will I be able to get the actual value out (since its stored on the sub-objects)?
Maybe the whole generic thing is indeed not quite the way to go after all :s
If you don't know the final set of parameter and the corresponding type of each parameter then the generics probably won't help - use object as a parameter value type.
Furthermore iterating through the list of parameters will be a pain since you'll have to examine the type of each item in order to determine how to treat the value.
What are you trying to achieve with generics ? Yes, they are cool (and going for boxing/unboxing is probably not a best idea), but in some cases you might want to use object instead (for both simplicity and flexibility).
-- Pavel
What you might want to introduce is an abstract base class for RegistrationValue<T> that is not generic, so that your ParameterRegistrationValue class can hold a non-generic reference, without needing knowledge of the type involved. Alternatively, it may be appropriate to make ParameterRegistrationValue generic also, and then add a non-generic base class for it instead (so that the list of values in ParameterRegistration can be of different types.
1st way:
public abstract class RegistrationValue
{
}
public class RegistrationValue<T> : RegistrationValue
{
public RegistrationValue(T value)
{
Value = value;
}
public T Value { get; private set; }
}
And now your code should compile.
Once you have a non-generic base class, I'd also move any members of the generic class that don't depend on the generic type parameters up into this base class. There aren't any in this example, but if we were instead modifying ParameterRegistrationValue to be generic, I'd move Parameter up into the non-generic base class (because it doesn't depend on the type parameter for RegistrationValue)
May be, you should use public RegistrationValue RegistrationValue, where T - is type, using in generic. For example, T - is String or other class or struct.
Or you should make class ParameterRegistrationValue as generic, to use generic argument in the field RegistrationValue.
I believe you want to have a collection of instances of different RegistrationValues-derived classes and be able to iterate it and for to have different type for each element. That's rather impossible.
You'll still need to cast each element to the type you know it is, because iterating the collection will return references to your base type (ParameterRegistrationValue - this one specified by IList type parameter). So it won't make any real difference from iterating over non-generic object list.
And if you can safely do that casting for each parameter (you know all the types), you probably don't need collection like this at all - it'll be better to have a class that encapsulates all the parameters in one type, so that you can call it with strong types, with IntelliSense etc. like this:
public class ParameterRegistration
{
public DateTime RegistrationDate { get; set; }
public PatientData PatientData { get; set; }
public Guid Identifier { get; set; }
// ...
}