I am trying to get a custom enum class working which should enable me to create enums with user friendly identifiers and an arbitrary associated value. so far so good:
public class EnumBase<T, E>
where E : class
{
private static readonly List<E> list = new List<E>();
private string text;
private T value;
public string Text { get { return text; } }
public T Value { get { return value; } }
public EnumBase(string text, T value)
{
this.text = text;
this.value = value;
list.Add(this as E);
}
protected static IEnumerable<E> ItemList
{
get { return list; }
}
}
public class Zahlungsart : EnumBase<int, Zahlungsart>
{
public static readonly Zahlungsart Erlagsschein = new Zahlungsart("Erlagsschein", 0);
public static readonly Zahlungsart Lastschrift = new Zahlungsart("Lastschrift", 1);
private Zahlungsart(string text, int value) : base(text, value) { }
public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}
And now my problem:
Console.WriteLine(Zahlungsart.ItemList.Count());
The following statement gives me 0, instead of 2. The problem is due to beforefieldinit, I think. I could work around this by calling some method of the specific enum directly which would force the static fields to load, but this is not the best solution, I think.
Hint: please do not propose some kind of [UserfriendlyName()]-attribute for enum here, I already know them.
EDIT
Thanks, hans. I had indeed a typo in my own code, calling the wrong generic specialisation.
Now my question is, can I get rid of the redefinition of ItemList in each subclass, but it seems this is necessary to to get the static fields initialized.
How about using "static constructor" ??
public class Zahlungsart : EnumBase<int, Zahlungsart>
{
public static readonly Zahlungsart Erlagsschein;
public static readonly Zahlungsart Lastschrift;
static Zahlungsart()
{
Erlagsschein = new Zahlungsart("Erlagsschein", 0);
Lastschrift = new Zahlungsart("Lastschrift", 1);
}
private Zahlungsart(string text, int value) : base(text, value) { }
public static new IEnumerable<Zahlungsart> ItemList { get { return EnumBase<int, Zahlungsart>.ItemList; } }
}
Your code doesn't repro the problem. But you will get a repro if you change the property like this:
public new static IEnumerable<Zahlungsart> ItemList {
get { return EnumBase<uint, Zahlungsart>.ItemList; } // Note: uint instead of int
}
Beware that every concrete class generated from a generic type will have its own static fields, they are not shared.
Related
I wrote the code below and i want to access the private varibale in another class, i created instance of the class and tried to access it but couldn't. can someone point out what I did wrong in the code below?
using System;
namespace lab_first
{
public class AccessModifiers
{
private int Abc { get; set; }
private int bcd { get; set; }
}
class Program
{
static void Main(string[] args)
{
var acc = new AccessModifiers();
Console.WriteLine(acc.Abc)
}
}
}
You make members private so that nobody outside the class can access them.
This goes inline with the principle of information hiding.
Your example should look like this:
public class AccessModifiers
{
// You can only access this inside of the class AccessModifiers
private int Abc { get; set; }
internal void SetValue(int x){
// Access possible, because SetValue() is inside the same class
Abc = x;
}
internal int GetValue(){
// Access possible, because GetValue() is inside the same class
return Abc;
}
}
class Program
{
static void Main(string[] args)
{
var acc = new AccessModifiers();
// Abc is never modified directly, only indirectly.
acc.SetValue(5);
Console.WriteLine(acc.GetValue());
}
}
However, there is still a way to access the private member. It's called Reflection. However, note that private variables are considered an implementation detail and might change at any time, so you can't rely on it. E.g. someone might change the name from Abc to def and your Reflection-based approach fails.
You can either change private to internal or public in this case.
Another way is declaring the variables in the class as private and using C# Properties in the class to set and get the values of variables. this is called encapsulation which is a protective shield that prevents the data from being accessed by the code outside this shield).
public class AccessModifiers
{
private int _abc { get; set; }
private int _bcd { get; set; }
public int Abc
{
get
{
return _abc;
}
set
{
_abc = value;
}
}
public int Bcd
{
get
{
return _bcd;
}
set
{
_bcd = value;
}
}
}
Is it possible to to define a string from a variable where the string does NOT have quotations. Example:
public class aclass
{
public string athing;
}
public void example(string thing)
{
aclass thing = new aclass();
}
The string thing can't be put into aclass thing = new aclass(); normaly.
Is there anyway to do it?
You need a constructor
void Main()
{
CreateExampleObject("testing");
}
public class Example
{
// This is a constructor that requires a string as an argument
public Example(string text)
{
this.Text = text;
}
public string Text { get; set; }
}
public void CreateExampleObject(string text)
{
Example example = new Example(text);
Console.WriteLine(example.Text);
}
You can do it this using many way but generally standard way is using constructor
please refer this link for better understanding.
C# : assign data to properties via constructor vs. instantiating
You have to ways of setting fields/property value of an object.
First is to do it through the constructor, as mentioned in other answer.
Second can be implmeneted in various ways:
Expose public property making field privte:
public class aclass
{
private string _athing;
public string Athing
{
get { return _athing; }
set { _athing = value; }
}
}
public void example(string thing)
{
aclass aclass = new aclass();
aclass.Athing = thing;
}
Or even shorter, you could use property:
public class aclass
{
public string Athing {get; set; }
}
Using your implementation, you make your field public, so you can set it easily:
public void example(string thing)
{
aclass aclass = new aclass();
aclass.athing = thing;
}
But it doesn't comply with OOP encapsulation principle.
I have several master objects. Each ot them has list of slave objects. Each of the slave objects has two fields: field1 and field2. I need to have access to the fields from the main objects ONLY if the main object, who asked for the field, is not an owner of the slave object.
class SlaveObj()
{
...
private readonly int field1;
private readonly string field2;
...
public int GetField1()
{
// if asker object is not my owner
// return field1
}
}
class MainObj()
{
...
List<SlaveObj> slaves = new List<SlaveObj>();
...
public int GetField1(MainObj other)
{
return other.slaves[0].GetField1();
}
}
First, what I tried, was this. I just tried to check, like in the first answer, what object is the asker. But I have something like Project1.MainObj for any instance of MainObj. So, I can't recognize whether the asker is the owner or not.
Code after changes (not works as i want)
class SlaveObj()
{
...
private MainObj owner;
private readonly int field1;
private readonly string field2;
...
public int GetField1(MainObj asker)
{
if(asker != owner) return field1;
}
}
class MainObj()
{
...
List<SlaveObj> slaves = new List<SlaveObj>();
...
public int GetField1(MainObj other)
{
return other.slaves[0].GetField1(this);
}
}
My friend, this should work out the way you need. But you gotta add IDs to parent objects.
internal class SlaveObj
{
private MainObj owner;
private readonly int field1;
private readonly string field2;
public SlaveObj(MainObj parent)
{
this.owner = parent;
}
public int GetFieldID(int askerID)
{
if (askerID != owner.ID) return field1;
return 0;
}
}
class MainObj
{
public int ID;
List<SlaveObj> slaves = new List<SlaveObj>();
public int GetFieldID(MainObj other)
{
return other.slaves[0].GetFieldID(this.ID);
}
public MainObj(int id)
{
this.ID = id;
}
}
And your previous version did not work out because your main objects are of reference type thich are compared by reference by default. So better use object IDs implement IEqualtyComparer in MainObj:
class MainObj : IEqualityComparer
It's easy to fix
class SlaveObj()
{
MainObj _owner;
readonly int _field1 = ...;
readonly string _field2 = ...;
// you need a way to set owner, e.g. constructor parameter
public SlaveObj(MainObj owner)
{
_owner = owner; // good example why underscore in field name is good
}
// return type: object
// renamed
// using C# 6.0 features to confuse people
public object GetFieldX(MainObj asker) => asker != _owner ? _field1 : _field2;
}
class MainObj()
{
List<SlaveObj> _slaves = new List<SlaveObj>();
// return first slave field value
// has nothing to do with instance, therefore static
// will return null if no slave
public static object GetFieldX(MainObj owner) => owner?.FirstOrDefault()?.GetFieldX(this);
}
but it's not pretty.
This is a pretty beginner question but I'm stumped and I can't figure out how to get what I want from this. I have my first class that obtains information (database/textfile/whatever) but I want it to relay that information into Class2.
For instance, the first:
public class Class1
{
private int first;
private string firstString;
private bool isTrue;
public void SomeMethod()
{
first = 1;
firstString = "FirstString";
isTrue = true;
}
}
Here SomeMethod sets all the attributes that I need to pass into Class2.
ClassTwo looks like
public class Class2
{
private int first;
private string FirstString;
private bool isTrue;
private int second;
private string SecondString;
private bool isFalse;
public void SomeOtherMethod()
{
}
}
Here what I want is for SomeOtherMethod() to set the first set of attributes with the values that were set in Class1's SomeMethod(). So that I can create an object of type Class2 and add what I want to it.
As some other commentators stated, you really should reuse your data definitions. Something like this can get you started:
public class Class1
{
private int _myInt;
private string _myString;
private bool _myBool;
public void SomeMethod()
{
_myInt = 1;
_myString = "FirstString";
_myBool = true;
}
}
public Class2
{
private Class1 _first = new Class1();
private Class1 _second = new Class1();
public void SetFirst(Class1 obj)
{
_first = obj;
}
}
and then use the classes like this:
Class1 c1 = new Class1();
Class2 c2 = new Class2();
c1.SomeMethod();
c2.SetFirst(c1);
You have to define get accessors for the properties of Class1 because they are all unreachable from outside the class and Class2 needs to use their values. Defining public properties with get accessors can be useful:
private int first;
public int First
{
get
{
return first;
}
}
Having every property in Class1 defined like this, you can access the values. After calling SomeMethod, two objects' properties can be equalized in two simple ways (See also: Signatures and overloading):
public void SomeOtherMethod()
{
Class1 tempClass = new Class1();
tempClass.SomeMethod();
this.first = tempClass.first;
this.FirstString = tempClass.firstString;
this.isTrue = tempClass.isTrue;
}
public void SomeOtherMethod(Class1 myClass) // Overloaded method
{
this.first = myClass.first;
this.FirstString = myClass.firstString;
this.isTrue = myClass.isTrue;
}
Even though the techniques above seem like to be what you asked for, the best is to initialize a class's properties using constructors. This way, you don't have to call SomeMethod each time you create a Class1 object, and you can also set its default values whenever a new one is created. Also, giving more general names to the properties will save you from duplicates. I write some code to provide you an understandable syntax that will prevent future problems of non-accessibility and repetition.
public class Class1
{
private int number;
public int Number
{
get { return number; }
}
private string name;
public string Name
{
get { return name; }
}
private bool isTrue;
public bool IsTrue
{
get { return isTrue; }
}
public Class1()
{
number = 1;
name = "FirstString";
isTrue = true;
}
public Class1(int value1, string value2, bool value3)
{
number = value1;
name = value2;
isTrue = value3;
}
}
public class Class2
{
private Class1 firstClass;
private Class1 secondClass;
public Class2()
{
firstClass = new Class1();
secondClass = new Class1(2, "SecondString", false);
}
}
If you're going to define many Class1 objects in Class2, then a solution such as an array or a list becomes must. I'll give a short example, see MSDN List page.
private List<Class1> class1List = new List<Class1>();
class1List.Add(new Class1());
class1List.Add(new Class1(2, "SecondString", false));
I get the impression that it's not. I have three integration tests that succeed when run individually, but when run in parallel, I get System.ArgumentException: An item with the same key has already been added.
I was sure hoping that ScenarioContext.Current always referred to the correct scenario, but it seems it's getting confused. Has anyone successfully added thread safety to this class? Or is there another approach I should be using for sharing values among step files?
ScenarioContext.Curent source:
public static ScenarioContext Current
{
get
{
if (current == null)
{
Debug.WriteLine("Accessing NULL ScenarioContext");
}
return current;
}
internal set { current = value; }
}
As you can see, it is not threadsafe
https://github.com/techtalk/SpecFlow/blob/master/Runtime/ScenarioContext.cs
This appears to be handled more nicely in SpecFlow V2: http://www.specflow.org/documentation/Parallel-Execution/
Extract (simpler of the options):
[Binding]
public class StepsWithScenarioContext : Steps
{
[Given(#"I put something into the context")]
public void GivenIPutSomethingIntoTheContext()
{
this.ScenarioContext.Set("test-value", "test-key");
}
}
I know this is a old post, but it's whell referenced, so this is my solution :
Just replace the ScenarioContext by a custom implementation like this :
public class ScenarioContextSafe
{
private static ScenarioContextSafe _current;
private static readonly object Locker = new object();
public static ScenarioContextSafe Current
{
get
{
lock (Locker) {
return _current ?? (_current = new ScenarioContextSafe());
}
}
}
public static void Reset()
{
lock (Locker) {
_current = null;
}
}
private readonly ConcurrentDictionary<string, object> _concurrentDictionary = new ConcurrentDictionary<string, object>();
public void Add(string key, object value)
{
_concurrentDictionary.TryAdd(key, value);
}
public void Set(object value, string key)
{
if (!_concurrentDictionary.ContainsKey(key))
_concurrentDictionary.TryAdd(key, value);
else
_concurrentDictionary[key] = value;
}
public void Remove(string key)
{
object result;
_concurrentDictionary.TryRemove(key, out result);
}
public T Get<T>(string key)
{
object result;
_concurrentDictionary.TryGetValue(key, out result);
return (T)result;
}
public bool ContainsKey(string key)
{
return _concurrentDictionary.ContainsKey(key);
}
public void Pending()
{
ScenarioContext.Current.Pending();
}
public ScenarioInfo ScenarioInfo{
get { return ScenarioContext.Current.ScenarioInfo; }
}
}
Then, create a hook for reset the context before each scenario
[BeforeScenario()]
public static void BeforeAllScenario()
{
ScenarioContextSafe.Reset();
}
I hope this help someone.