how to set private structure fields in a public property? - c#

I have a structure:
public struct ServiceDescription
{
string serviceDescriptionText;
string serviceLogoRef;
/// <summary>
/// The position to print the service on the label.
/// </summary>
int servicePosition;
/// <summary>
/// Constructor
/// </summary>
/// <param name="serviceDescriptionText"></param>
/// <param name="serviceLogoRef"></param>
/// <param name="servicePosition"></param>
public ServiceDescription(string serviceDescriptionText, string serviceLogoRef,
int servicePosition)
{
this.serviceDescriptionText = serviceDescriptionText;
this.serviceLogoRef = serviceLogoRef;
this.servicePosition = servicePosition;
}
}
and a property:
public string pServiceDescription
{
get
{
return p_sServiceDescription;
}
// set private structure field 1
// set private structure field 2
// etc...
}
How do I set each of the private fields of the structure in the setters of my property?

It is usually a very bad idea to have mutable structs; mutable value-type semantics is not what people usually expect. You can, however, simply add a set that works like any other regular setter. It just isn't a very good idea:
public string Text
{
get { return text; }
set { text = value; } // this is a really bad idea on a struct
}
If it was me, that would be an immutable struct with private readonly fields and a constructor that sets all of them (and get-only properties), or a class - probably with automatically implemented properties, i.e.
public class ServiceDescription {
public string Text {get;set;}
//...
}

Related

C# NET Looping over object properties stored in List

At the moment I'm working on funcionality that involves exporting and importing data to Xlsx file. Here's what I want to do: I want to have an attribute I can put above a property like this.
public class MyClass
{
[XlsxColumn("Column 1")]
public string myProperty1 { get; set; }
public int myProperty2 { get; set; }
}
So far I don't have problems, but then I want to "store references" to properties marked with the XlsxColumn attribute. I'm using reflection
to store properties data in List
var propsList = MyClass.GetProperties().Where(
prop => Attribute.IsDefined(prop, typeof(XlsxColumn)));
I have a list with all properties marked with XlsxColumn (only myProperty1 in this example).
EDIT: The problem is I don't know how to loop over properties in MyClass, but only properties with XlsxColumn attribute (so all PropertyInfo objects stored in propsList variable), without resorting to reflection with each object saved to Xlsx file.
I'm restricted to .NET 4.0.
Thanks for your time.
MyClass.GetProperties() does not work because you have to get the type of the class to invoke the GetProperties method. Otherwise you are invoking a static method called GetProperties defined in the MyClass class.
var propsList = typeof(MyClass).GetProperties().Where(
prop => prop.IsDefined(typeof(XlsxColumnAttribute), false)).ToList();
If you just want the names (IList<string>):
var propsList = typeof(Excel).GetProperties().Where(
prop => prop.IsDefined(typeof(XlsxColumnAttribute), false))
.Select(prop=> prop.Name)
.ToList();
to use .Where you have to include System.Linq
I must say that I am not sure if this is the solution you are looking for. Because I could not quite make out what your question is. Well I have tried to provide an answer as much as I could figure out.
I went for a static class for CachingPropetyProvider but you can go for an instance class and use a dependency injection library and use it as a Singleton too. Moreover, I have written extensive comments so It is as self explanatory as possible.
Let us define MyClass. I also deliberately changed it a little bit.
public class MyClass
{
[XlsxColumn("Column 1")]
public string MyProperty1 { get; set; }
[XlsxColumn("Column 2")]
public int MyProperty2 { get; set; }
}
I also defined a MetaInfo class to hold the cached information.
public class MetaInfo {
/// <summary>
/// Immutable class for holding PropertyInfo and XlsxColumn info.
/// </summary>
/// <param name="info">PropertyInfo</param>
/// <param name="attr">XlsxColumn</param>
public MetaInfo(PropertyInfo info, XlsxColumn attr) {
PropertyInfo = info;
Attribute = attr;
}
/// <summary>
/// PropertyInfo. You may want to access the value inside the property.
/// </summary>
public PropertyInfo PropertyInfo { get; }
/// <summary>
/// Attribute. You may want to access information hold inside the attribute.
/// </summary>
public XlsxColumn Attribute { get; }
}
And lastly the main guy. This guy is responsible for providing all the data about classes
public class CachingPropProvider {
/// <summary>
/// Holds the meta information for each type.
/// </summary>
private static readonly ConcurrentDictionary<Type, List<MetaInfo>> TypeCache;
/// <summary>
/// Static constructor is guaranteed to run only once.
/// </summary>
static CachingPropProvider() {
//Initialize the cache.
TypeCache = new ConcurrentDictionary<Type, List<MetaInfo>>();
}
/// <summary>
/// Gets the MetaInfo for the given type. Since We use ConcurrentDictionary it is thread safe.
/// </summary>
/// <typeparam name="T">Type parameter</typeparam>
public static IEnumerable<MetaInfo> GetCachedStuff<T>() {
//If Type exists in the TypeCache, return the cached value
return TypeCache.GetOrAdd(typeof(T),Factory);
}
/// <summary>
/// Factory method to use to extract MetaInfo when Cache is not hit.
/// </summary>
/// <param name="type">Type to extract info from</param>
/// <returns>A list of MetaInfo. An empty List, if no property has XlsxColumn attrbiute</returns>
private static List<MetaInfo> Factory(Type #type) {
//If Type does not exist in the TypeCahce runs Extractor
//Method to extract metainfo for the given type
return #type.GetProperties().Aggregate(new List<MetaInfo>(), Extractor);
}
/// <summary>
/// Extracts MetaInfo from the given property info then saves it into the list.
/// </summary>
/// <param name="seedList">List to save metainfo into</param>
/// <param name="propertyInfo">PropertyInfo to try to extract info from</param>
/// <returns>List of MetaInfo</returns>
private static List<MetaInfo> Extractor(List<MetaInfo> seedList,PropertyInfo propertyInfo) {
//Gets Attribute
var customattribute = propertyInfo.GetCustomAttribute<XlsxColumn>();
//If custom attribute is not null, it means it is defined
if (customattribute != null)
{
//Extract then add it into seed list
seedList.Add(new MetaInfo(propertyInfo, customattribute));
}
//Return :)
return seedList;
}
}
Finally let us see how to use the solution. It is pretty straightforward actually.
//Has 2 values inside
var info = CachingPropProvider.GetCachedStuff<MyClass>();

Settings Design for ASP.NET Application

First of all, I have been looking online for a Settings Design Pattern but I haven't been able to find a solution that works in my case or only cryptic answers like Use Dependency Injection.
The Problem
I have a large ASP .NET solution which is deployed to multiple production environments. Many decisions in code are taken based on settings which have been implemented in the Web.config file (a few hundreds). At the moment they are all accessed using the NameValueCollection ConfigurationManager.AppSettings. I want to move these settings in the database such that I can create a user interface and modify them more easily afterwards.
I would also prefer for the settings to remain accessible from the Web.config such that if something happens with the database, the application won't break.
Solution Architecture
Basically, the solution consists of the following projects:
UI (this is were the Web.config file resides)
BLL
DAL
Integration Project 1 (the application interracts with other applications. This project uses configuration settings like web addresses, authentication information etc. which at the moment are passed as parameters in the methods - which I personally find very ugly)
Integration Project 2
...
The Code
The Setting class (the database table is practically the same). SettingType is an enum which defines the type of the Setting: Int, String, Bool and I defined for the UI.
public class Setting
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; set; }
/// <summary>
/// Gets or sets the name of the setting.
/// </summary>
/// <value>
/// The name of the setting.
/// </value>
public string Name { get; set; }
/// <summary>
/// Gets or sets the type of the setting.
/// </summary>
/// <value>
/// The type of the setting.
/// </value>
public SettingType Type { get; set; }
/// <summary>
/// Gets or sets the setting value.
/// </summary>
/// <value>
/// The setting value.
/// </value>
public object Value { get; set; }
/// <summary>
/// Gets or sets the setting description.
/// </summary>
/// <value>
/// The setting description.
/// </value>
public string Description { get; set; }
/// <summary>
/// Gets or sets the setting key.
/// </summary>
/// <value>
/// The setting key.
/// </value>
public string Key { get; set; }
/// <summary>
/// Gets or sets the default value
/// </summary>
/// <value>
/// The default value
/// </value>
public string Default { get; set; }
}
The SettingHelper class (which does everything at the moment, will split functionality in the future):
public static class SettingHelper
{
// Settings collection
private static List<Setting> _settings;
/// <summary>
/// Reloads the settings.
/// </summary>
/// <exception cref="System.Exception"></exception>
public static void LoadSettings()
{
_settings = new List<Setting>();
// Code which loads the settings from the database
}
private static Setting GetSetting(string key)
{
try
{
// if settings are not loaded, we reload them from the database
if (_settings == null || _settings.Count == 0)
LoadSettings();
var value = from Setting setting in _settings
where setting != null && setting.Key == key
select setting;
return value.FirstOrDefault();
}
catch (Exception)
{
return null;
}
}
public static void SetSetting(string key, object newValue, int userID)
{
var currentSetting = GetSetting(key);
if (currentSetting != null && !Convert.ToString(currentSetting.Value).ToUpper().Equals(Convert.ToString(newValue).ToUpper()))
{
// Code which updates the setting value
}
}
// For the UI
public static IEnumerable<Setting> GetAllSettings()
{
if (_settings == null)
LoadSettings();
return _settings;
}
// To change back swiftly to the Web.config in case there are errors in production - will remove in the future
public static bool SettingsFromDataBase
{
get
{
if (HttpContext.Current.Application["SettingsFromDataBase"] == null)
HttpContext.Current.Application["SettingsFromDataBase"] = ConfigurationManager.AppSettings["SettingsFromDataBase"];
bool settingsFromDataBase;
if (bool.TryParse(HttpContext.Current.Application["SettingsFromDataBase"] as string, out settingsFromDataBase))
return settingsFromDataBase;
else return false;
}
}
public static T ObjectToGenericType<T>(object obj)
{
if (obj is T)
{
return (T)obj;
}
else
{
try
{
return (T)Convert.ChangeType(obj, typeof(T));
}
catch (InvalidCastException)
{
return default(T);
}
}
}
public static T GetSetting<T>(string key)
{
if (SettingsFromDataBase)
{
var setting = GetSetting(key);
return setting != null
? ObjectToGenericType<T>(setting.Value)
: ObjectToGenericType<T>(ConfigurationManager.AppSettings[key]);
}
if (HttpContext.Current.Application[key] == null)
HttpContext.Current.Application[key] = ConfigurationManager.AppSettings[key];
return (T)HttpContext.Current.Application[key];
}
// The actual settings which will be used in the other projects
public static string StringSetting
{
get { return GetSetting<string>("StringSetting"); }
}
public static bool BoolSetting
{
get { return GetSetting<bool>("BoolSetting"); }
}
Note: Likely there are improvements to this class using Reflection, but I would prefer to avoid it (apart from that conversion).
Questions
At the moment the SettingHelper resides in the UI project (in order to be able to access the settings from the Web.config). How can I transmit these settings in the BLL or Integration projects?
Also, do you think this implementation with all the settings stored in a static list is the way to go? It feels unoptimal.
Any help or discussion on improvements is appreciated. Thank you.

Automapper is not transferring my collection items

I am using AutoMapper 4.x.
I have a couple of classes as follows:
/// <summary>
/// All service outputs need to descend from this class.
/// </summary>
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
private readonly OzCpResultErrors _OzCpResultErrors;
public OzCpAppServiceOutputBase()
{
_OzCpResultErrors = new OzCpResultErrors();
}
public OzCpResultErrors ResultErrors
{
get { return _OzCpResultErrors; }
}
public bool ResultSuccess
{
get { return _OzCpResultErrors.Messages.Count == 0; }
}
}
/// <summary>
/// Return from the booking service when a simple booking is made.
/// </summary>
public class OzCpSimpleManualCruiseBookingOutput : OzCpAppServiceOutputBase
{
public int OzBookingId { get; set; }
}
}
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput
{
}
My issue comes in when I call AutoMapper to translate between OzCpSimpleManualCruiseBookingOutput and SimpleManualCruiseBookingOutput is that the ResultErrors is cleared.
public SimpleManualCruiseBookingOutput SimpleManualCruiseBooking(SimpleManualCruiseBookingInput aParams)
{
OzCpSimpleManualCruiseBookingOutput result = _PlatformBookingService.SimpleManualBooking(Mapper.Map<OzCpSimpleManualCruiseBookingInput>(aParams));
//**TESTING
result.ResultErrors.AddFatalError(1, "Oh Dear!!!!");
//**As soon as I perform the mapping the ResultErrros collection loses the item I have added above
return Mapper.Map<SimpleManualCruiseBookingOutput>(result);
}
I am guessing it is because it is a read only property, but I cannot figure out how to make it transfer the collection.
Any help greatly appreciated.
EDIT
I have also tried adding the items in the collection myself so changing my mapping from:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>();
to using the after map function as follows:
Mapper.CreateMap<OzCpSimpleManualCruiseBookingOutput, SimpleManualCruiseBookingOutput>()
.AfterMap((src, dst) => dst.ResultErrors.Messages.AddRange(src.ResultErrors.Messages));
but this then results in the destination having TWO items in the list instead of 1 viz:
which are both the same entry of "Oh Dear!!!!"
SOLUTION
Using the private setter approach suggested by DavidL (and an upgrade to Automapper 4.x) meant I got the required behaviour. So this is what I ended up with:
/// <summary>
/// Defines the contract for all output DTO's to platform
/// application services.
/// </summary>
/// <seealso cref="OzCpAppServiceOutputBase" />
public interface IOzCpAppServiceOutputBase : IOutputDto
{
/// <summary>
/// Contains a list of errors should a call to an application service fail.
/// </summary>
OzCpResultErrors ResultErrors{ get; }
/// <summary>
/// When TRUE the underlying call to the application service was successful, FALSE
/// otherwise. When FALSE see ResultErrors for more information on the error condition.
/// </summary>
bool ResultSuccess { get; }
}
public class OzCpAppServiceOutputBase : IOzCpAppServiceOutputBase
{
public OzCpAppServiceOutputBase()
{
ResultErrors = new OzCpResultErrors();
}
/// <remarks>The private setter is here so that AutoMapper works.</remarks>
public OzCpResultErrors ResultErrors { get; private set; }
public bool ResultSuccess
{
get { return ResultErrors.Messages.Count == 0; }
}
}
So while needing to add a private setter "just for" AutoMapper that is a small price to pay to have this work and not use complicated mappings to deal with the issue.
With the current inheritance structure, AutoMapper will NOT be able to do what you want it to do. Since your destination structure has the same properties as your source structure, the properties are also readonly. AutoMapper will not map to readonly properties that do not have a setter declared.
You have a few options:
Make the property setter explicitly private. This answer suggests that later versions of AutoMapper support this functionality. In this case it works for 4.x.
Make the property setter internal, so that only members of this assembly can set it. Since latest versions of AutoMapper will map to private setters, they should also map to internal setters.
Make the property settable.
Downcast the object instead of mapping (you've mentioned you don't want to do this because your object structures will eventually diverge).
Shadow the property on the destination object with a public setter. Ugly and a good source of strange bugs.
public class SimpleManualCruiseBookingOutput : OzCpSimpleManualCruiseBookingOutput
{
public new OzCpResultErrors ResultErrors { get; set; }
}
Create a helper that maps your read-only properties via reflection. DO NOT DO THIS!
PropertyInfo nameProperty = aParams.GetType().GetProperty ("ResultErrors");
FieldInfo nameField = nameProperty.GetBackingField ();
nameField.SetValue (person, aParams.ResultErrors);

Access child's variable in parent passed through function parameter

I am trying to access some specific variable that are only available in a child class. But the problem is that I recieve the parent of this class by parameter. Even with casting I can't seem to be able to access the members. Can it be done?
public class ENUMTranslator : ITranslate<RedisData>
{
public string Translate(RedisData message)
{
string bitMask = message.AssociatedParam.ParamDictionary["Bitmask"];
var enumerations = (EnumParams)message.AssociatedParam.EnumDictionary
}
}
The thing is that the data is not in message itself but inside AssociatedParam Which is the parent class of EnumParams.
The EnumDictionary is what I am trying to access that should be in EnumParams, but I just can't access it.
EDIT : Here is the EnumParam class.
message.AssociatedParams
is a GAPParam
public class EnumParams : GAPParam
{
#region Class Members
/// <summary>
/// Dictionary for the enums linking name with hex value
/// </summary>
private Dictionary<string, string> _enumDictionary;
#endregion // Class Members
#region Properties
/// <summary>
/// Dictionary for the enums linking name with hex value
/// </summary>
public Dictionary<string, string> EnumDictionary
{
get { return _enumDictionary; }
set { _enumDictionary = value; }
}
#endregion // Properties
#region Constructor
/// <summary>
/// Initialise the dictionaries
/// </summary>
public EnumParams()
{
_enumDictionary = new Dictionary<string, string>();
}
#endregion // Constructor
}
I cannot see it with intellisense and it would not compile either.
Well you could cast message.AssociatedParam to an EnumParams:
var enumerations = ((EnumParams)message.AssociatedParam).EnumDictionary
but if message.AssociatedParam is not castable to an EnumParams then it will fail at runtime. Some way to mitigate the risk:
should EnumDictionary be on GAPParam instead? Even if it's virtual or abstract?
should message.AssociatedParam be an EnumDictionary instead of a GAPParam?
do a check before casting to make sure message.AssociatedParam is an EnumParams - but then what do you do if its not?

How to serialize a dictionary to an XML file?

I'm trying to maintain a dictionary of configurations.
Here is my abstract class.
[Serializable]
public abstract class Configuration
{
}
And here is a concrete class (for the moment, I just have only this class).
[Serializable]
public class BinaryProblemConfiguration : Configuration
{
[XmlAttribute]
public decimal MinValue { get; set; }
[XmlAttribute]
public decimal MaxValue { get; set; }
}
I've got a class which contains a Dictionary of configuration levels.
The first parameter is the name of the configuration. When name="" means default configuration.
Level means the difficulty. There are three levels: Easy, Medium and Hard.
And the third one is the configuration.
/// <summary>
/// The abstract level configuration allows descendent classes to configure themselves
/// </summary>
public abstract class LevelConfiguration
{
private Dictionary<string, Dictionary<Levels, Configuration>> _configurableLevels = new Dictionary<string, Dictionary<Levels, Configuration>>();
/// <summary>
/// Adds a configurable level.
/// </summary>
/// <param name="level">The level to add.</param>
/// <param name="problemConfiguration">The problem configuration.</param>
protected void AddConfigurableLevel(string name, Levels level, Configuration problemConfiguration)
{
if (!_configurableLevels.ContainsKey(name))
{
_configurableLevels.Add(name, new Dictionary<Levels, Configuration>());
}
_configurableLevels[name].Add(level, problemConfiguration);
}
/// <summary>
/// Returns all the configurable levels.
/// </summary>
/// <param name="level"></param>
protected void RemoveConfigurableLevel(string name, Levels level)
{
_configurableLevels[name].Remove(level);
}
/// <summary>
/// Returns all the configurable names.
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetConfigurationNames()
{
return _configurableLevels.Keys;
}
/// <summary>
/// Returns all the configurable levels.
/// </summary>
/// <returns></returns>
public IEnumerable<Levels> GetConfigurationLevels(string name)
{
return _configurableLevels[name].Keys;
}
/// <summary>
/// Gets the problem configuration for the specified level
/// </summary>
/// <param name="level">The level.</param>
/// <returns></returns>
public Configuration GetProblemConfiguration(string name, Levels level)
{
return _configurableLevels[name][level];
}
}
This is the class which create some configurations. I'm creating three default configs and two customs.
public class AdditionLevelConfiguration : LevelConfiguration
{
public AdditionLevelConfiguration()
{
AddConfigurableLevel("", Levels.Easy, GetEasyLevelConfiguration());
AddConfigurableLevel("", Levels.Medium, GetMediumLevelConfiguration());
AddConfigurableLevel("", Levels.Hard, GetHardLevelConfiguration());
AddConfigurableLevel("config2", Levels.Easy, GetEasyLevelConfiguration());
AddConfigurableLevel("config2", Levels.Medium, GetMediumLevelConfiguration());
var configs = this.GetProblemConfiguration("config2", Levels.Medium);
var configs2 = this.GetProblemConfiguration("", Levels.Easy);
}
protected Configuration GetHardLevelConfiguration()
{
return new BinaryProblemConfiguration
{
MinValue = 100,
MaxValue = 1000,
};
}
protected Configuration GetMediumLevelConfiguration()
{
return new BinaryProblemConfiguration
{
MinValue = 10,
MaxValue = 100,
};
}
protected Configuration GetEasyLevelConfiguration()
{
return new BinaryProblemConfiguration
{
MinValue = 1,
MaxValue = 10,
};
}
}
I plan to write these configurations in a XML file. I was thinking of serialize them, but it throws me an error. What should I do?
Another option you may consider is using a DataContractSerializer. I was able to serialize your dictionary of dictionaries this way.
Things to keep in mind if you go this route:
You would have to add different attributes. Specifically, you need DataContract on the type and DataMember on the properties.
You need to ensure all properties have setters, even if the setters ultimately are private.
When creating your DataContractSerializer, you need to ensure it is aware of all your types. Giving it the type of your dictionary takes care of string, Levels, and Configuration, but not BinaryProblemConfiguration. Additional type info can be provided via additional constructor overloads.
Example:
var dict = new Dictionary<string,Dictionary<Levels,Configuration>> ();
var wtr = XmlWriter.Create (Console.Out);
var dcSerializer = new DataContractSerializer (dict.GetType (), new [] {typeof (BinaryProblemConfiguration)});
dcSerializer.WriteObject (wtr, dict);
If you do the above, you could also switch to DataContractJsonSerializer later for a more compact JSON format if you prefer (assuming XML is not a hard requirement, of course).
From what i know classes that implement IDictionary cannot be Xml serialized.
Try this http://weblogs.asp.net/pwelter34/archive/2006/05/03/444961.aspx, it worked for me.

Categories