I'm playing around with Dictionaries and the new fancy 4.0 dynamic types inside a dictionary.
I have a Dictionary:
Dictionary<dynamic, dynamic> dynamicDic
And I populate it like this:
dynamicDic.Add("First", new Class1());
dynamicDic.Add("Second", new Class2());
For the sake of testing/practising Class1 and Class2 are quite simple:
public class Class1
{
public string Element { get; set; }
public List<Class2> Class2 { get; set; }
}
public class Class2
{
public string Property { get; set; }
public string Field;
}
I create two other classes that map class1 and class2 and they are virtually the same so ClassMap1 and ClassMap2. I'll just include CalssMap1 though:
public class ClassMap1: BaseClassMap1
{
public ClassMap1()
{
var r = new Class1();
Children = new Dictionary<string, dynamic>
{
{"Element", r.GetType().GetProperty("Element")},
{"Class1", r.GetType().GetProperty("Class1")}
};
Name = "Root";
ObjectType = typeof (Class1);
Parent = "RootElement";
HasParent = false;
HasChildren = true;
IsClass = r.GetType().IsClass;
}
}
And I create a base class: BaseClass1()
public class BaseClass1
{
private String _Name;
public String Name
{
get { return _Name; }
set { _Name = value; }
}
private Type _ObjectType;
public Type ObjectType
{
get { return _ObjectType; }
set { _ObjectType = value; }
}
private String _Parent;
public String Parent
{
get { return _Parent; }
set { _Parent = value; }
}
private Dictionary<string, dynamic> _Children;
public Dictionary<string, dynamic> Children
{
get { return _Children; }
set { _Children = value; }
}
private bool _HasParent;
public bool HasParent
{
get { return _HasParent; }
set { _HasParent = value; }
}
private bool _HasChildren;
public bool HasChildren
{
get { return _HasChildren; }
set { _HasChildren = value; }
}
private bool _IsClass;
public bool IsClass
{
get { return _IsClass; }
set { _IsClass = value; }
}
}
I populate the classes with data, not really important what data :)
Yet when I try to access the values through a Linq statement:
var a = _classObjects.SingleOrDefault(x => x.Key == node.Name).Value;
a only gives me:-
a.Equals(), a.GetType(), a.GetEnumerator() or a.ToString()
I would like to be able to have it do this instead (with intellisense)...
a.Children
a.Name
a.HasParent
etc...
Anyone got any ideas where I'm going wrong?
Oops got that completely wrong... Sorry :|
Edited above...
dynamic classes are all about run-time (NOT compile-time) discovery. How do you expect Intellisense to know what to do?
Using dynamic classes incurs a high performance overhead. I really suggest that you make it: Dictionary<string, dynamic> dynamicDic.
Or define a MyBaseClass and make it: Dictionary<string, MyBaseClass> myDic.
Related
So right now I am trying to design a new hire program that grants access to active directory groups, generates documents with their information and location.
Right now I am doing this with an enumeration, with a switch statement that sets the details on the ViewModel like this:
case CaneRidgeSettings.Departments.SCSC:
Model.ScannerFolder = #"scan1\Supply Chain Service Center\" + Model.UserId;
Model.ExtensionRanges = "list station 8000 to-ext 8349";
Model.AdministrativeAssistant = Loader.SCSCAdminAssistant;
Model.DuoCode = "Franklin TN - 8175";
Model.PrinterSelectedIndex = (int)CaneRidgeSettings.PrinterGroups.Cane_Ridge_5th_Floor_West;
return await find.FindNextComputer("800SCSC");
The problem I have with this design is that if I ever add more departments to this building, I have to manually update this switch. So I tried a few things around this such as a dictionary, but it didn't seem to bind to a combo-box very well (even when implementing my own INotifyCollectionChanged).
So instead I created an interface that contains this information, for simplicity and length lets just say the interface does this:
public interface IDepartmentInfo
{
string DepartmentName { get; }
List<string> ActiveDirectoryGroups { get; }
string AdministrativeAssistant { get; }
string Floor { get; }
}
I then created a new class that implements this interface
public class SCSC : IDepartmentInfo
{
public string DepartmentName { get; } = "Shared Services";
public List<string> ActiveDirectoryGroups { get; } = new List<string>() {"Example_AD_GRP","Domain_Users"};
public string AdministrativeAssistant { get; } = "Lisa_Smith#outlook.com";
public string Floor { get; } = "5th Floor East";
public override string ToString() => DepartmentName;
}
Then, on my main Building Class I have an observable collection that expects an IDepartmentInfo and initializes those departments
public class CaneRidgeBuilding : IBuilding
{
public ObservableCollection<IDepartmentInfo> Departments { get; set; } = new ObservableCollection<IDepartmentInfo>() {new SCSC(), new ARS()};
public override string ToString()
{
return "CaneRidge";
}
}
On my View Model I implemented a few properties, mainly the BuildingSelectedIndex and the DepartmentSelectedIndex.
I also have an IDepartmentInfo property that notifies when it is changed because it is databound to several labels on my UI.
public class MainWindowViewModel : BindableBase
{
public ObservableCollection<IBuilding> Buildings { get; set; } = new ObservableCollection<IBuilding>() { new CaneRidgeBuilding() };
private ObservableCollection<IDepartmentInfo> _departmentInfos = new ObservableCollection<IDepartmentInfo>();
public ObservableCollection<IDepartmentInfo> DepartmentInfos
{
get { return _departmentInfos; }
set { SetProperty(ref _departmentInfos, value); }
}
private int _buildingIndex = -1;
public int BuildingIndex
{
get { return _buildingIndex; }
set
{
SetProperty(ref _buildingIndex, value);
SetDepartments();
}
}
private void SetDepartments()
{
if (BuildingIndex != -1)
DepartmentInfos = Buildings[BuildingIndex].Departments;
}
private int _departmentIndex = -1;
public int DepartmentIndex
{
get { return _departmentIndex; }
set
{
SetProperty(ref _departmentIndex, value);
LoadDepartmentSettings();
}
}
private IDepartmentInfo _departmentInformation;
public IDepartmentInfo DepartmentInformation
{
get { return _departmentInformation; }
set { SetProperty(ref _departmentInformation, value); }
}
private void LoadDepartmentSettings()
{
if (DepartmentIndex != -1)
DepartmentInformation = DepartmentInfos[DepartmentIndex];
}
private string _title = "Prism Application";
public string Title
{
get { return _title; }
set { SetProperty(ref _title, value); }
}
public MainWindowViewModel()
{
}
}
And it works exactly the way I want it to, however to problem I am running into now is how would I handle dependency injection? If I have 10 departments implementing IDepartmentInfo, how exactly could I pass this to an observable collection?
Because the moment I introduce a new building, if I tell Unity to resolve all IDepartmentInfos, what is going to happen is I'll get every single department even if it doesn't belong to CaneRidge.
If I split the departments to each building, then I run into issues where I can't easily load the departments into the ViewModel, because it is expecting an IDepartmentInfo collection. If I limited it to just one type of collection, then it wouldn't work.
Am I over-complicating things?
Here is an idea.
Custom attribute
Introduce a BuilingAttribute so each IDepartmentInfo implementation can declare Type of the building it belongs to (allow multiple if one department can belong to multiple buildings, I got the idea it can't).
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class BuildingAttribute : Attribute
{
public Type BuildingType { get; private set; }
public BuildingAttribute(Type buildingType)
{
this.BuildingType = buildingType;
}
}
DepartmentInfo Collection Factory
An interface that knows how to create a collection of DepartmentInfo for each building Type.
public interface IDepartmentInfoCollectionFactory
{
void RegisterDepartment<T>(Func<IDepartmentInfo> departmentCreator) where T : class, IBuilding;
ObservableCollection<IDepartmentInfo> GetDepartments<T>() where T : class, IBuilding;
}
And the implementation (will be registered as singleton).
public class DepartmentInfoCollectionFactory : IDepartmentInfoCollectionFactory
{
private readonly Dictionary<Type, List<Func<IDepartmentInfo>>> departmentCreators =
new Dictionary<Type, List<Func<IDepartmentInfo>>>();
void IDepartmentInfoCollectionFactory.RegisterDepartment<T>(Func<IDepartmentInfo> departmentCreator)
{
Type buildingType = typeof(T);
if (!this.departmentCreators.ContainsKey(buildingType))
this.departmentCreators.Add(buildingType, new List<Func<IDepartmentInfo>>());
if (!this.departmentCreators[buildingType].Contains(departmentCreator))
this.departmentCreators[buildingType].Add(departmentCreator);
}
ObservableCollection<IDepartmentInfo> IDepartmentInfoCollectionFactory.GetDepartments<T>()
{
Type buildingType = typeof(T);
if (!this.departmentCreators.ContainsKey(buildingType))
throw new InvalidOperationException(
string.Format("No departments have been registered for {0}.", buildingType.ToString()));
ObservableCollection<IDepartmentInfo> departmentInfos = new ObservableCollection<IDepartmentInfo>();
foreach(Func<IDepartmentInfo> creator in this.departmentCreators[buildingType])
{
departmentInfos.Add(creator());
}
return departmentInfos;
}
}
Configuring the factory, so it knows how to create IDepartmentInfo collections.
protected override void ConfigureContainer()
{
Container.RegisterType<IDepartmentInfoCollectionFactory, DepartmentInfoCollectionFactory>(
new ContainerControlledLifetimeManager());
this.ConfigureDepartmentInfoCollectionFactory(Container.Resolve<IDepartmentInfoCollectionFactory>());
}
private void ConfigureDepartmentInfoCollectionFactory(IDepartmentInfoCollectionFactory factory)
{
// Types implementing IDepartmentInfo
var deptInfoTypes = AppDomain.CurrentDomain
.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(t => typeof(IDepartmentInfo).IsAssignableFrom(t) && !t.IsInterface);
foreach(Type type in deptInfoTypes)
{
// Get collection of BuildingAttribute for the type
var buildingAttributes = type.GetCustomAttributes(typeof(BuildingAttribute), false)
.OfType<BuildingAttribute>();
if (buildingAttributes.Count() < 1)
throw new InvalidOperationException(
string.Format("The type {0} didn't declare BuildingArgument.", type.ToString()));
var buildingType = buildingAttributes.First().BuildingType;
if (buildingType == null || !buildingType.GetInterfaces().Contains(typeof(IBuilding)))
throw new InvalidOperationException(
string.Format("{0}: BuildingType is not an IBuilding.", type.ToString()));
var registerMethod = typeof(IDepartmentInfoCollectionFactory).GetMethod("RegisterDepartment")
.MakeGenericMethod(new Type[] { buildingType });
registerMethod.Invoke(factory, new object[]
{
new Func<IDepartmentInfo>(() => (IDepartmentInfo)Container.Resolve(type))
});
}
}
Inject the factory.
public class FooBuilding : IBuilding
{
private IDepartmentInfoCollectionFactory factory;
private readonly ObservableCollection<IDepartmentInfo> departmentInfos;
public string Name { get; } = "FooBuilding";
public ObservableCollection<IDepartmentInfo> DepartmentInfos
{
get { return this.departmentInfos; }
}
public FooBuilding(IDepartmentInfoCollectionFactory factory)
{
this.factory = factory;
this.departmentInfos = factory.GetDepartments<FooBuilding>();
}
}
Adding new department
It doesn't require any editing, just create new class with the attribute.
[Building(typeof(FooBuilding))]
public class BarDepartment : IDepartmentInfo
{
public string Name { get; } = "Bar department";
}
I was able to figure out how to inject different buildings and departments, probably not the best way
EDIT: Updated it to use reflection to make it less maintenance
protected override void ConfigureContainer()
{
base.ConfigureContainer();
Container.RegisterTypes(AllClasses.FromLoadedAssemblies()
.Where(type => typeof(IDepartment).IsAssignableFrom(type)), WithMappings.FromAllInterfaces, WithName.TypeName, WithLifetime.None);
ObservableCollection<IBuilding> Buildings = new ObservableCollection<IBuilding>()
{
Container.Resolve<Building1>(new ParameterOverride("departments",GetDepartmentCollection("Building1"))),
Container.Resolve<Building2>(new ParameterOverride("departments",GetDepartmentCollection("Building2")))
};
Container.RegisterInstance(typeof(ObservableCollection<IBuilding>), Buildings,
new ExternallyControlledLifetimeManager());
}
private ObservableCollection<IDepartment> GetDepartmentCollection(string buildingName)
{
var departments = new List<IDepartment>();
foreach (var registration in Container.Registrations.Where( s => s.MappedToType.Namespace.Contains(buildingName)))
{
departments.Add((IDepartment)Container.Resolve(registration.MappedToType));
}
return new ObservableCollection<IDepartment>(departments);
}
Now I am able to completely eliminate the enumeration and it can be extended in the future without breaking any code or requiring me to change anything.
All the objects in our system inherit a base class which has got a property of type object.
I have tried adding protoignore attribute to all the properties of the base class as well but that doesn't seem to work as well.
class Program
{
static void Main(string[] args)
{
Vehicle vehicle = new Vehicle();
vehicle.BodyStyleDescription = "4x4";
vehicle.BodyStyleText = "Prestige Medium";
dynamic protobufModel = TypeModel.Create();
AddTypeToModel<Vehicle>(protobufModel);
using (MemoryStream compressed = new MemoryStream())
{
using (GZipStream gzip = new GZipStream(compressed, CompressionMode.Compress, true))
{
protobufModel.Serialize(gzip, vehicle);
}
string str = Convert.ToBase64String(compressed.GetBuffer(), 0, Convert.ToInt32(compressed.Length));
}
}
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T).GetProperties().Select(p => p.Name).OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
}
Following is the hierarchy of the object
public interface IObjectBaseClass
{
[ProtoIgnore()]
object Parent { get; set; }
[ProtoIgnore()]
bool IsSaved { get; set; }
[ProtoIgnore()]
string XmlAtLoad { get; set; }
}
public class ObjectBaseClass : IObjectBaseClass
{
public ObjectBaseClass()
{
}
[ProtoIgnore()]
internal object _Parent;
[ProtoIgnore()]
internal bool _IsSaved;
[ProtoIgnore()]
internal string _XmlAtLoad;
[ProtoIgnore()]
public bool IsSaved
{
get { return _IsSaved; }
set { _IsSaved = value; }
}
[ProtoIgnore()]
public object Parent
{
get { return _Parent; }
set { _Parent = value; }
}
[ProtoIgnore()]
public string XmlAtLoad
{
get { return _XmlAtLoad; }
set { _XmlAtLoad = value; }
}
}
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
Your problem is that when you do typeModel.Add(typeof(T), true).Add(properties.ToArray()) you are adding all properties of T to the runtime type model, including those marked with ProtoIgnore. You can see this by calling the debugging method protobufModel.GetSchema(typeof(Vehicle)) which returns:
message Object {
}
message Vehicle {
optional string BodyStyleDescription = 1;
optional string BodyStyleText = 2;
optional bool IsSaved = 3;
optional Object Parent = 4;
optional string XmlAtLoad = 5;
}
To avoid adding properties marked with [ProtoIgnore], you could do:
public static MetaType AddTypeToModel<T>(RuntimeTypeModel typeModel)
{
var properties = typeof(T)
.GetProperties()
.Where(p => !p.GetCustomAttributes<ProtoIgnoreAttribute>().Any())
.Select(p => p.Name)
.OrderBy(name => name);
return typeModel.Add(typeof(T), true).Add(properties.ToArray());
}
Alternatively, since you are manually annotating some of your models with protobuf attributes anyway, you could mark the derived types with [ProtoContract(ImplicitFields = ImplicitFields.AllPublic)], e.g.:
[ProtoContract(ImplicitFields = ImplicitFields.AllPublic)]
public class Vehicle : ObjectBaseClass
{
private string _BodyStyleText;
private string _BodyStyleDescription;
public string BodyStyleDescription
{
get { return _BodyStyleDescription; }
set { _BodyStyleDescription = value; }
}
public string BodyStyleText
{
get { return _BodyStyleText; }
set { _BodyStyleText = value; }
}
}
Using either method, the schema for Vehicle becomes:
message Vehicle {
optional string BodyStyleDescription = 1;
optional string BodyStyleText = 2;
}
This is what you require.
i want to cast a string from database to a class object without having to go over each possible outcome.
so not
if(type.StartsWith("ContactPersonType")){//} else if(type.StartsWith("ContactPersonTitle")){//}
this is what i have so far
private static T Create<T>(IDataRecord record)
{
var properties = typeof(T).GetProperties();
var returnVal = Activator.CreateInstance(typeof(T));
properties.ToList().ForEach(item =>
{
string type = item.GetMethod.ReturnParameter.ParameterType.Name;
if (type.StartsWith("ContactPerson"))
{
Type t = Type.GetType(item.GetMethod.ReturnParameter.ParameterType.ToString());
item.SetValue(returnVal, Convert.ChangeType(record[item.Name].ToString(), t));
}
else if (!type.StartsWith("ObservableCollection"))
{
item.SetValue(returnVal, Convert.ChangeType(record[item.Name].ToString(), item.PropertyType));
}
});
return (T)returnVal;
}
public class ContactPersonType
{
private int _id;
public int ID
{
get { return _id; }
set { _id = value; }
}
private String _name;
public String Name
{
get { return _name; }
set { _name = value; }
}
}
thanks
Use an anonymous collection when you want a certain action to apply to different input values.
foreach(var option in new[] {"ContactPerson", "ContactPersonTitle" }){
if (type.StartsWith(option))
{
Type t = Type.GetType(item.GetMethod.ReturnParameter.ParameterType.ToString());
item.SetValue(returnVal, Convert.ChangeType(record[item.Name].ToString(), t));
}
}
I define a class property algorithm as follows:
public InputParametersProperty InputParameters { get; set; }
public class InputParametersProperty
{
private Dictionary<string, object> inputParameters = new Dictionary<string, object>();
public object this[string name]
{
get { return inputParameters[name]; }
set
{
if (inputParameters == null)
inputParameters = new Dictionary<string, object>();
else
inputParameters.Add(name, value);
}
}
}
From another class I want to use the property of the form:
algorithm.InputParameters["populationSize"] = 100;
But I get the error: Object reference not set to an instance of an object
You're never instantiating the InputParameters property to anything. That's why you're gettin NullReferenceException.
Change:
public InputParametersProperty InputParameters { get; set; }
to:
private InputParametersProperty _inputParameters;
public InputParametersProperty InputParameters
{
get
{
return _inputparameters ?? (_inputparameters = new InputParametersProperty());
}
}
I have a similar problem like this :
Many to many object to object relation in C#
However, imagine that the Championship would have a "Last Date Played" property (just as an example) that would map to any Participant. In this case, where would that property end up? Is it a must to create an intermediate class? (which i wouldn't want to do) what option do i have? thanks!
One way would be to have an array on each object containing pointers to the other objects either via an dictionary that stores the object as key and date as value (or a custom property class for any number of properties) or using a wrapper class around the object and a plain list, this wrapper should then implement the decorator pattern to allow direct access to the object together with any unique properties.
The wrapper object could use an internal object for the properties that is shared between the oposing wrapper objects for the 2 different objects so that any property is in sync.
Another way would be a separate list of pairs where one is wrapped like the above.
The later makes it easy to loop over all objects.
Here is a code example, it might not be exactly what you need but it might give you the basics of my idea.
void Main()
{
var p = new Player("David");
var c = new Championship("Chess");
p.LinkChampionship(c, DateTime.Now);
p.Dump();
}
// Define other methods and classes here
class Player : Properties {
public virtual String Name {get; set;}
public List<ChampionshipWrapper> champs = new List<ChampionshipWrapper>();
public Player() {
}
public Player(string name) {
Name = name;
}
public void LinkChampionship(Championship champ, DateTime when) {
var p = new Properties(when);
champs.Add(new ChampionshipWrapper(champ, p));
champ.players.Add(new PlayerWrapper(this, p));
}
}
class Championship : Properties {
public virtual String Name { get; set; }
public List<PlayerWrapper> players = new List<PlayerWrapper>();
public Championship(){}
public Championship(string name) {
Name = name;
}
public void LinkPlayer(Player play, DateTime when) {
var p = new Properties(when);
players.Add(new PlayerWrapper(play, p));
play.champs.Add(new ChampionshipWrapper(this, p));
}
}
class Properties {
public virtual DateTime LastPlayed { get; set; }
public Properties() {
}
public Properties(DateTime when) {
LastPlayed = when;
}
}
class PlayerWrapper : Player {
private Player player;
private Properties props;
public PlayerWrapper(Player play, Properties prop) {
this.player = play;
this.props = prop;
}
public override String Name {
get { return this.player.Name; }
set { this.player.Name = value; }
}
public override DateTime LastPlayed {
get { return this.props.LastPlayed; }
set { this.props.LastPlayed = value; }
}
}
class ChampionshipWrapper : Championship {
private Championship champ;
private Properties props;
public ChampionshipWrapper(Championship c, Properties prop) {
this.champ = c;
this.props = prop;
}
public override String Name {
get { return this.champ.Name; }
set { this.champ.Name = value; }
}
public override DateTime LastPlayed {
get { return this.props.LastPlayed; }
set { this.props.LastPlayed = value; }
}
}