Pointing to a property without reflection or databinding - c#

I want to create a class with a property that "variably" points to some other property in another class.
Imagine a class (called "Limiter") with several integer properties (Limit1, Limit2, etc).
I now want a second class ("LimitWatcher") which can "watch" one of those limits. But I want to be able to set which particular limit it is watching in the constructor. I eventually want several instances of LimitWatcher, each one pointing to a separate Limit. The Limit values themselves may change after the Watchers have been instantiated, but the watcher must always see the current value of the Limit that it is watching. So basically, I want to store a reference to an integer.
I know I can accomplish this using reflection (see example below), but I feel as though there might be a simpler way.
using System;
namespace ConsoleApplication4
{
public class Limiter
{
public int limit1 { get; set; } = 10;
public int limit2 { get; set; } = 20;
public void Update()
{
limit1++;
limit2++;
}
}
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
}
private Limiter myLimiter { get; }
public string limitName { get; set; }
//can I do this without reflection:
public int FooLimit { get { return (int)typeof(Limiter).GetProperty(limitName).GetValue(myLimiter); } }
}
class Program
{
static void Main(string[] args)
{
Limiter lim = new ConsoleApplication4.Limiter();
LimitWatcher w1 = new LimitWatcher(lim, nameof(lim.limit1));
LimitWatcher w2 = new LimitWatcher(lim, nameof(lim.limit2));
lim.Update();
Console.WriteLine($"1st watcher sees {w1.FooLimit}"); //11
Console.WriteLine($"2nd watcher sees {w2.FooLimit}"); //21
Console.ReadKey();
}
}
}

You could use a Func int the constructor, something like:
private Limiter limiter;
private Func<Limiter, int> propertyAccesor;
public LimitWatcher(Limiter lim, string propName, Func<Limiter, int> propertyAccesor)
{
this.propertyAccesor = propertyAccesor;
}
public bool LimitExceeded()
{
int propertyValue = propertyAccesor(limiter);
return propertyValue > 20;
}

You could use dynamic expressions:
using System.Linq.Expressions;
public class LimitWatcher
{
public LimitWatcher(Limiter lim, string propName)
{
myLimiter = lim;
limitName = propName;
var parameter = Expression.Parameter(typeof(Limiter), "x");
var member = Expression.Property(parameter, propName);
var finalExpression = Expression.Lambda<Func<Limiter, int>>(member, parameter);
getter = finalExpression.Compile();
}
private Func<Limiter, int> getter;
private Limiter myLimiter { get; }
public string limitName { get; set; }
public int FooLimit { get { return getter(myLimiter); } }
}
Inspired by this article

Related

How to create a structure with embedded fields?

I am looking for information about that in the internet but with no success. The goal is to realize a sort of dataset of 10 subject (sub_1, sub_2... sub_10), each of them has done 3 kind of activities (walk, run, jump) for three time each (trial_1... trial_3) with relative scores. I would like to access these information like:
variable = dataset.sub_1.jump.trial_2.score;
or, at least:
variable = dataset.sub[0].task[2].trial[1].score;
So, the structure would be a tree structure. Until now I only realized a structure with "parallel fields":
struct dataset
{
public string[] sub; // 1 to 10 subjects
public string[] task; // 1 to 3 tasks
public string[] trial; // 1 to 3 trials
public int score; // the score of the above combination
}
Any idea?
This problem can be solved in many ways.
My solution has one drawback, there is no check if user exceeded Score arrays capacity.
I guess database tag has nothing to do with this question
using System;
using System.Linq;
namespace ConsoleApp
{
public abstract class Task
{
public string Name { get; set; }
public int TotalScore { get { return Score.Sum(); } }
public int[] Score { get; set; } = new int[3];
}
public class Walk : Task { }
public class Run : Task { }
public class Jump : Task { }
public class Subject
{
public Walk Walk { get; set; } = new();
public Run Run { get; set; } = new();
public Jump Jump { get; set; } = new();
public int TotalScore { get { return Walk.TotalScore + Run.TotalScore + Jump.TotalScore; }}
}
class Program
{
static void Main(string[] args)
{
var subject = new Subject();
// Adding score to specific trials
subject.Run.Score[0] = 50;
subject.Run.Score[1] = 40;
subject.Run.Score[2] = 60;
subject.Jump.Score[0] = 40;
subject.Jump.Score[1] = 80;
subject.Jump.Score[2] = 100;
// Output score of 1. trial for Walk task
Console.WriteLine(subject.Walk.Score[0]);
// Output total score as a sum of all trials for Jump task
Console.WriteLine(subject.Jump.TotalScore);
// Output total score as a sum of all trials in all tasks
Console.WriteLine(subject.TotalScore);
// ERROR CASE: this will be exception
subject.Jump.Score[3] = 100;
}
}
}
using System;
using System.Collections.Generic;
namespace ConsoleApp
{
public class Trial
{
public Trial(int score)
{
Score = score;
}
public int Score { get; set; }
}
public class Task
{
public List<Trial> Trials { get; } = new List<Trial>();
}
public class Subject
{
public Dictionary<string, Task> Tasks { get; } = new Dictionary<string, Task>();
public Subject()
{
Tasks.Add("walk", new Task());
Tasks.Add("run", new Task());
Tasks.Add("jump", new Task());
}
}
class Program
{
static void Main(string[] args)
{
Subject player1 = new Subject();
player1.Tasks["run"].Trials.Add(new Trial(score: 3));
Console.WriteLine(player1.Tasks["run"].Trials[0].Score);
}
}
}
Maybe a class for everything is too much, but maybe you want to add a description property for tasks one day or a timestamp for the trial. Then it's ok.
public class Subject
{
private Dictionary<string,Activity> _activities { get; }= new Dictionary<string, Activity>();
public Activity this[string activity]
{
get
{
if (!_activities.Keys.Contains(activity))
_activities[activity] = new Activity();
return _activities[activity];
}
set
{
_activities[activity] = value;
}
}
public int Score => _activities.Values.Sum(x => x.Score);
}
public class Activity
{
private Dictionary<int, Trial> _trials { get; } = new Dictionary<int, Trial>();
public Trial this[int trial]
{
get
{
if (!_trials.Keys.Contains(trial))
_trials[trial] = new Trial();
return _trials[trial];
}
set
{
_trials[trial] = value;
}
}
public int Score => _trials.Values.Sum(x => x.Score);
}
public class Trial
{
public int Score { get; set; }
}
public class Answer
{
public void DoSomething()
{
Subject Mindy = new Subject();
Mindy["curling"][1].Score = 5;
Mindy["bowling"][1].Score = 290;
Console.WriteLine(Mindy.Score);
}
}
This is what I would guess you think you need... but from your question I think you're still new to C# and might want to rethink your concept. It looks like a very database-oriented way of looking at the problem, so maybe you might want to take a look at dapper to more closely match your database.
Also, avoid using the classname Task, this can imo only cause confusion if you ever start using multithreading (System.Threading.Task is a .NET framework component)

how to declare a class using the new keyword as property in a static class in c#

I am currently building a namespace to handle complicated string actions. because I use the this string keyword, I must declare where the functions and properties are located as static. (the name of this class is "StringExtension") now I have another class named StringExtensionSettings and I use its boolean properties to determent what functions in the class StringExtension will be enabled. (for the user to choose what functions he wants to use and what not)
ex:
public class StringExtensionSettings
{
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
I don't want to warp the string in a class because it will make it complicated for the user. is there is any way to enable or disable function in a static class based on another class properties? and/or how to declare a class within a static class?
thank you in advance!
Additional resources:
the StringExtension class:
static class StringExtension
{
//this is what I'm trying to declare: gives an error
public StringExtensionSettings StringSettings = new StringExtensionSettings();
public static string AddMidSubString(this string Str, string MidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
public static string RandomMix(this string Str)
{
char[] array = Str.ToCharArray();
Random rng = new Random();
int n = array.Length;
while (n > 1)
{
n--;
int k = rng.Next(n + 1);
var value = array[k];
array[k] = array[n];
array[n] = value;
}
return new string(array);
}
// and more functions...
Follow-up of my comment in the OP
Within a Singleton (class), you are still able/ allowed to define fields.
The singleton design pattern is an interface. It is a popular class
type for programs. It allows a class to enforce that it is only
allocated (read -> created) once.
public sealed class StringExtensionSettings
{
private StringExtensionSettings()
{
}
private static StringExtensionSettings instance = null;
public static StringExtensionSettings Instance
{
get
{
if (instance == null)
{
instance = new StringExtensionSettings();
}
return instance;
}
}
public bool DecryptString { get; set; } = true;
public bool EncryptString { get; set; } = true;
public bool RandomMix { get; set; } = true;
public bool AddMidSubString { get; set; } = true;
}
Usage:
Single Field call
StringExtensionSettings.Instance.AddMidSubString
Implementation
public static string AddMidSubString(this string Str, string MidSubString)
{
if (StringExtensionSettings.Instance.AddMidSubString)
{
StringBuilder Result = new StringBuilder(Str);
Result.Insert(Result.Length / 2, MidSubString);
return Result.ToString();
}
throw new Exception($"Not allowed to call {nameof(AddMidSubString)}");
}
Summarized; calling StringExtensionSettings.Instancecreates a new instance of StringExtensionSettings, only (once!), when the private field instance of StringExtensionSettings is null.

Using Enumeration Class

I'm new to C# and I'm relatively new to abstract classes and inheritance and I'm having troubles understanding how to use them. I have this abstract enumeration class:
public abstract class Enumeration : IComparable
{
public uint Id { get; private set; }
public string Name { get; private set; }
public uint MaxTemperature { get; private set; }
public double Density { get; private set; }
protected Enumeration()
{
}
protected Enumeration(uint id, string name, uint maxTemprature, double density)
{
Id = id;
Name = name;
MaxTemperature = maxTemprature;
Density = density;
}
public static IEnumerable<T> GetAll<T>() where T : Enumeration,
new()
{
var type = typeof(T);
var fields = type.GetTypeInfo().GetFields(BindingFlags.Public
| BindingFlags.Static | BindingFlags.DeclaredOnly);
foreach (var info in fields)
{
var instance = new T();
var locatedValue = info.GetValue(instance) as T;
if (locatedValue != null)
{
yield return locatedValue;
}
}
}
public override bool Equals(object obj)
{
var otherValue = obj as Enumeration;
if (otherValue == null)
{
return false;
}
var typeMatches = GetType().Equals(obj.GetType());
var valueMatches = Id.Equals(otherValue.Id);
return typeMatches && valueMatches;
}
public int CompareTo(object other)
{
return Id.CompareTo(((Enumeration)other).Id);
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
This class is inherited by my material class:
class Material : Enumeration
{
public static readonly Material FreeSpace =
new Material(0, "Free Space", 0, 0);
public static readonly Material CarbonSteel =
new Material(1, "Carbon Steel", 2500, 0.284);
private Material()
{
}
private Material(uint id, string name, uint maxTemperature,
double density) : base(id, name, maxTemperature, density)
{
}
private static IEnumerable<Material> List()
{
return new[] { FreeSpace, CarbonSteel };
}
}
Now I want to use these materials in my part class:
class Part
{
private Material partMaterial;
public Part() { }
public Material PartMaterial
{
set
{
partMaterial = value;
}
}
}
This is where I'm stuck, how do I set a variable as one of the enumerated static objects so I can get the properties from those?
You can use SelectedItem instead of SelectedIndex
part.PartMaterial = (Material) MaterialCombo.SelectedItem;
So, I wish I would have left the question the way it was, because in the end it was the correct way to ask the question. But after the snide comments and down grading I changed it to what I thought was better. The way the original question should have been answered was:
Since you are enumerating the materials class, you need a method to expose the Enumerated values of the objects. The
IEnumerable<Material> List() method should be made public to accomplish this.
You can then use MaterialCombo.DataSource = Material.List() to populate the combobox with the material objects and MaterialCombo.DisplayMember = "Name"; to display the names of those objects in the combobox.
Finally, use #Oxald's answer to pass the material to your part class.
Thank you #Mark Benningfield for pointing me in the direction to search for "Using an enum to populate a combobox" which was helpful.
And Oxald for suggesting to use .SelectedItem instead of .SelectedIndex.

passing around values to an AutoMapper Type Converter from outside

I have a multilingual database, which returns values based on a key and an enum Language. When I convert a DB object to a model, I want the model to contain the translated value based on the key and the current language.
The key comes from the DB object but how can I pass the current language to the the Mapper.Map() function?
Currently, I am using a [ThreadStatic] attribute to set the culture before calling Mapper.Map<>, and to retrieve it in the TypeConverter.
public enum Language
{
English, French, Italian, Maltese
}
public class MultilingualValue<T>
{
public Dictionary<Language, T> Value { get; set; }
public MultilingualValue()
{
this.Value = new Dictionary<Language, T>();
}
}
public class PersonData
{
public string FirstName { get; set; }
public MultilingualValue<string> City { get; set; }
}
public void MapPerson()
{
PersonData personData = new PersonData();
personData.FirstName = "John";
personData.City = new MultilingualValue<string>();
personData.City.Value[ Language.English] = "The Zurrieq";
personData.City.Value[Language.French] = "Le Zurrieque";
MultilingualValueData.CurrentLanguage = Language.English;
var personModel = Mapper.Map<PersonData, PersonModel>(personData);
}
public class MultilingualValueToBasicDataTypeConverter<T> : ITypeConverter<MultilingualValue<T>, T>
{
public T Convert(ResolutionContext context)
{
var currentLanguage = MultilingualValueData.CurrentLanguage; //THIS IS THE [ThreadStatic] VARIABLE
if (currentLanguage == null) throw new InvalidOperationException("Please make sure to fill in CurrentLanguage");
MultilingualValue<T> sourceMultilingualValue = (MultilingualValue < T > )context.SourceValue;
T destinationValue = default(T);
if (sourceMultilingualValue != null)
{
destinationValue = sourceMultilingualValue.Value[currentLanguage.Value];
}
return destinationValue;
}
}
public static class MultilingualValueData
{
[ThreadStatic]
public static Language? CurrentLanguage;
}
I left out the configurations as I think they're unneccessary for this example. If you need them, I'll post them as well.
While this works, I find this workaround quite ugly. Is there any way to pass data through the ResolutionContext?
Just use the Map overload that takes a Action<IMappingOperationOptions>. You can add configuration elements to the Items property that are then passed to your ITypeConverter
public class CustomConverter : ITypeConverter<string, string>
{
public string Convert(ResolutionContext context)
{
return "translated in " + context.Options.Items["language"];
}
}
internal class Program
{
private static void Main(string[] args)
{
AutoMapper.Mapper.CreateMap<string, string>().ConvertUsing<CustomConverter>();
var result = AutoMapper.Mapper.Map<string, string>("value" , opt => opt.Items["language"] = "english");
Console.Write(result); // prints "translated in english"
Console.ReadLine();
}
}

C# Avoid Multiple SWITCH Statements .net

Please excuse bursts of stupidity as I learn the intricacies of C# / .NET
Say I have three classes with multiple static properties (more than three but for arguments sake..)
CLASS FOO
public static A
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS BAR
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
CLASS YOO
{
get / set A;
}
public static B
{
get / set B;
}
public static C
{
get / set C;
}
And from another class I need to update one or several static properties in each class multiple times... How do I keep from writing multiple SWITCH statments like this...
public void updateVarx(string class, string varx)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.A = Varx;
break;
case BAR:
BAR.A = Varx;
break;
case YOO:
YOO.A = Varx;
break;
}
}
And then another one when I want to update B varY:
public void updateVary(string class, string vary)
{
string y = 'class'
SWITCH (y)
{
case FOO:
FOO.B = Vary;
break;
case BAR:
BAR.B = Vary;
break;
case YOO:
YOO.B = Vary;
break;
}
}
Since you are learning .net/c#, I guess i should warn you, using static properties is probably not the way to go in object oriented programming.
Static is global state and is dangerous. If you end up using multi-threaded code, you have to be super careful. If you need only one instance, just instantiate one, but don't go creating static properties on a class, unless you have a pretty good reason to add them (And I can't think of any right now).
In fact, in well designed, object oriented code you sould probably not have many if, switch, getters or setters either.
Let's say you need different behaviors on your classes, you can do it this way.
Interface ISecurity {
void UpdateVarX(int value);
void UpdateVarY(int value);
int GetValueX();
int GetValueX();
}
class Foo:ISecurity {
// Implement methods of the interface
}
class Bar:ISecurity {
// Implement methods of the interface
}
class Yoo:ISecurity {
// Implement methods of the interface
}
// This class is the class that uses your other classes
class Consumer
{
private ISecurity sec;
public Consumer(ISecurity sec) {
sec.UpdateVarX(25);
}
}
Or if as in your example, all your static classes have the same properties:
public class Settings {
public int A {get; set;}
public int B {get; set;}
public int C {get; set;}
}
public class NeedsToUseOtherClass {
public NeedsToUseOtherClass() {
Settings foo = new Settings();
Settings bar = new Settings();
Settings yoo = new Settings();
foo.setA(25);
}
}
Maybe I am not understanding the problem but if all your classes have the same exact properties then you can just pass the object (FOO, BAR, or YOO) into UpdateVarx or UpdateVary methods and just implement an interface? Something along these lines:
public class FOO : IHasStatus
{
public A
{
get / set A;
}
public B
{
get / set B;
}
public C
{
get / set C;
}
}
public void updateVarx(IHasStatus someObject, string varx)
{
someObject.A = varx;
}
public void updateVary(IHasStatus someObject, string vary)
{
someObject.B = vary;
}
If you don't need the concrete classes, you can abstract out the logic like so:
public class Status {
public string A {
get; set;
}
public string B {
get; set;
}
public string C {
get; set;
}
}
public static class StatusManager {
private static Dictionary<string, Status> statusMap = new Dictionary<string,Status>();
public static Status GetStatus(string name) {
Status status;
if (!statusMap.TryGetValue(name, out status))
statusMap[name] = status = new Status();
return status;
}
public static void SetStatus(string name, Status status) {
statusMap[name] = status;
}
public static void UpdateVarx(string name, string varx) {
GetStatus(name).A = varx;
}
// ...
}
If you are a fan of the javascript way of solving multiple switch cases like this
you can always wrap up the switch handlers as Actions and toss them in a Dictionary.
For example : (Source obtained from here)
public class SwitchCase : Dictionary<string,Action>
{
public void Eval(string key)
{
if (this.ContainsKey(key))
this[key]();
else
this["default"]();
}
}
//Now, somewhere else
var mySwitch = new SwitchCase
{
{ "case1", ()=>Console.WriteLine("Case1 is executed") },
{ "case2", ()=>Console.WriteLine("Case2 is executed") },
{ "case3", ()=>Console.WriteLine("Case3 is executed") },
{ "case4", ()=>Console.WriteLine("Case4 is executed") },
{ "default",()=>Console.WriteLine("Default is executed") },
};
mySwitch.Eval(c);
Below code uses all kinds of hacks, not really recommended in production code unless you have a very good reason.
using System;
using System.Linq;
namespace ConsoleApplication1
{
static class Program
{
private static void SetStaticProperty(string className, string propName, string varx)
{
//This sucks, I couldnt find the namespace with easily through reflection :(
string NAMESPACE = "ConsoleApplication1";
Type t = Type.GetType(NAMESPACE + "." + className);
t.GetProperties().Where(p => p.Name == propName).First().SetValue(null, varx, null);
}
public static void updateVarx(string className, string varx)
{
SetStaticProperty(className, "A", varx);
}
public static void updateVary(string className, string vary)
{
SetStaticProperty(className, "B", vary);
}
static void Main(string[] args)
{
updateVarx("Foo", "FooAstring");
updateVarx("Bar", "BarAstring");
updateVarx("Yod", "YodAstring");
updateVary("Foo", "FooBstring");
updateVary("Bar", "BarBstring");
updateVary("Yod", "YodBstring");
Console.WriteLine(Foo.A);
Console.WriteLine(Foo.B);
Console.WriteLine(Bar.A);
Console.WriteLine(Bar.B);
Console.WriteLine(Yod.A);
Console.WriteLine(Yod.B);
Console.ReadLine();
}
}
class Foo
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Bar
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
class Yod
{
public static string A { get; set; }
public static string B { get; set; }
public static string C { get; set; }
}
}
You can use dictionary as configuration and remove the switch statement
Create a dictionary and add append data as below for mapping
//Have dictionary setted up
Dictionary<string, dynamic> m_Dictionary = new Dictionary<string, dynamic>();
m_xmlDictionary.Add("classA",FOO);
m_xmlDictionary.Add("classB",BAR);
m_xmlDictionary.Add("classC",BAR);
//Have dictionary setted up
//change the function as below
public void updatevarx(string class, string varx)
{
m_Dictionary[class].A=varx // Replaced switch statement
}
//while calling use
updatevarx("classC","abc!");// This will assign BAR.A with abc!

Categories

Resources