I want to create a list of names and access it as a strongly typed enum. For eg.
string foo = FileName.Hello; //Returns "Hello.txt"
string foo1 = FileName.Bye; //Returns "GoodBye.doc"
Or it could be an object like:
Person p = PeopleList.Bill; //p.FirstName = "Bill", p.LastName = "Jobs"
How do I create a datatype like this?
Although the question is strange or not completely explained, here is the literal solution:
Option 1:
public static class FileName
{
public const string Hello = "Hello.txt";
public const string GoodBye= "GoodBye.doc";
}
Option 2:
public class Person
{
public string FirstName {get; set; }
public string LastName {get; set; }
public Person(string firstName, string lastName)
{
this.FirstName = firstName;
this.LastName = lastName;
}
}
public static class PeopleList
{
public static Person Bill = new Person("Bill", "Jobs");
}
just use a Dictionary<People, Person> for that:
enum People { Bill, Bob};
var myDict = new Dictionary<People, Person>();
myDict.Add(People.Bill, new Person() { FirstName = "Bill", LastName = "Jobs" });
now you can get Bill back with this syntax:
Person p = myDict[People.Bill];
You can you Extension Methods on your Enum object to return specific values.
Here's an article on CodeProject that will show you how to create an attribute that you can apply to each enumeration member to give it some "extra" data (like your filename, in this case) that you can use elsewhere in code.
You can use a struct (http://msdn.microsoft.com/en-us/library/ah19swz4(v=VS.100).aspx)
You can use static class with values..
public static class PeopleList
{
public static readonly Person Bill = new Person("Bill", "Jobs");
public static readonly Person Joe = new Person("Joe", "Doe");
}
public static class FileNames
{
public static readonly string Hello = "Hello.txt";
public static readonly string Bye = "Byte.txt";
}
then you can reference them as PeopleList.Bill or FileNames.Hello. It won't have the same properties as an enum and your methods will need to take a string or Person as parameter.
This is an over the top solution using attributes for your second example. Note this code has a lot of problems and is just an example.
public static T GetValue<T>(this Enum e) where T:class
{
FieldInfo fi = e.GetType().GetField(e.ToString());
var valueAttribute = fi.GetCustomAttributes(typeof (ValueAttribute),
false).FirstOrDefault() as ValueAttribute;
if (valueAttribute != null) return valueAttribute.Value as T;
return null;
}
class PersonValueAttribute : ValueAttribute
{
public PersonValueAttribute(string firstName, string lastName)
{
base.Value = new Person {FirstName = firstName, LastName = lastName};
}
}
class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public static implicit operator Person(Enum e)
{
return e.GetValue<Person>();
}
}
enum PeopleList
{
[PersonValue("Steve", "Jobs")]
Steve
}
Allowing for simple usage:
Person steve = PeopleList.Steve;
Console.WriteLine(steve.FirstName); //Steve
I would use the Description attribute to attach custom data to an enum. Then you can use this method to return the value of the description:
public static string GetEnumDescription(Enum value)
{
FieldInfo fi = value.GetType().GetField(value.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
string description = (attributes.Length > 0) ? attributes[0].Description : string.Empty;
return description;
}
Related
public class Person {
string Name
string Address
int Age
.. 100+ more columns
}
var result = new List<Person>();
foreach (var item in result )
{
//loop column and trim the values.
}
I want the simplest way to loop the columns (assuming 100+ columns) where datatype is string then trim the value.
To rephrase in more C# terms: I want to update all properties and fields of an object that are of type string with trimmed value as item.StringProp = item.StringProp.Trim(). I don't want to manually write update for each property.
You could use reflection and Linq for filtering the properties of type string. From the OP, it looks like you are using Fields instead of properties. Please note it is unclear whether the Properties/Fields are public from OP, if you need to use public fields/properties, please use BindingFlags.Public
public List<T> TrimList<T>(List<T> source)
{
foreach(var property in typeof(T).GetFields(BindingFlags.NonPublic | BindingFlags.Instance).Where(x=>x.FieldType== typeof(string)))
{
foreach(var personItem in source)
property.SetValue(personItem,Convert.ToString(property.GetValue(personItem)).Trim());
}
return source;
}
If properties, you could use
public List<T> TrimList<T>(List<T> source)
{
foreach(var property in typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).Where(x=>x.PropertyType== typeof(string)))
{
foreach(var personItem in source)
property.SetValue(personItem,Convert.ToString(property.GetValue(personItem)).Trim());
}
return source;
}
Demo Code
Note: prior to .NET 4.5 you need to pass null as a second argument:
public List<T> TrimList<T>(List<T> source)
{
foreach(var property in typeof(T).GetProperties(BindingFlags.NonPublic | BindingFlags.Instance).Where(x=>x.PropertyType== typeof(string)))
{
foreach(var personItem in source)
property.SetValue(personItem,Convert.ToString(property.GetValue(personItem,null)).Trim());
}
return source;
}
As well as reflection, another way is to make it the responsibility of the Person class.
public class Person {
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
.. 100+ more columns
public void DoTrim()
{
this.Name = this.Name.Trim();
this.Address = this.Address.Trim();
... still need to code 100+ properties
}
}
The advantage is that you can call it like this
var result = new List<Person>();
...
for(int i=0; i < result.Count(); i++)
{
result[i].DoTrim();
}
Or you can control your data in the Person class when you set it and use local private variables.
public class Person {
private string name;
public string Name
{
get { return name; }
set { name = value.Trim(); }
}
private string address;
public string Address
{
get { return address; }
set { address= value.Trim(); }
}
....
This is how I would implement it:
class Program
{
static void Main(string[] args)
{
var obj = new Person
{
MyProperty = " A",
MyProperty1 = " A ",
MyProperty2 = "A ",
MyProperty3 = "A A A",
};
TrimStrings(obj);
}
public static void TrimStrings(object obj)
{
Type stringType = typeof(string);
var properties = obj.GetType().GetProperties().Where(x => x.PropertyType == stringType);
foreach(var property in properties)
{
string value = (string)property.GetValue(obj);
property.SetValue(obj, value?.Trim());
}
}
}
public class Person
{
public string MyProperty { get; set; }
public string MyProperty1 { get; set; }
public string MyProperty2 { get; set; }
public string MyProperty3 { get; set; }
}
Output:
{"MyProperty":"A","MyProperty1":"A","MyProperty2":"A","MyProperty3":"A
A A"}
You can use This Nuget Package
.After Install use it as bellow:
result.ForEach(x => x.AdjustString());
I hope it becomes clear what I mean. I have multiple static class full of options:
static class Thing1
{
public const string Name = "Thing 1";
// More const fields here.
}
static class Thing2
{
public const string Name = "Thing 2";
// More const fields here.
}
Now I want to use those options to create a class which includes the contents of one of these classes.
public void Create<T>()
{
var foo = new Foo(T.Name);
foo.Prop = T.Something;
if (T.HasValue)
foo.Add(T.Value);
}
But of course this doesn't work. I would use interfaces, but static classes can't implement interfaces.
Is there any way to make this work elegantly? Making Thing1 and Thing2 singletons would work, but that isn't a very nice solution.
I could create a struct and put the objects into another static class, but I was wondering whether you could do something like the above.
Well, you can create an interface and make your classes non-static and inherit from this interface:
public class Thing1 : IThing
{
public string Name { get; } = "Thing 1";
// More const fields here.
}
public class Thing2 : IThing
{
public string Name { get; } = "Thing 2";
// More fields here.
}
interface IThing
{
string Name { get; }
}
And then use it for your method together with type parameter constraint:
public void Create<T>(T t) where T : IThing
{
// Now compiler knows that `T` has all properties from `IThing`
var foo = new Foo(t.Name);
foo.Prop = t.Something;
if (t.HasValue)
foo.Add(t.Value);
}
You can try Reflection: scan assemblies for static classes, obtain public const string fields with their values from them and materialize them as a Dictionary<T>
using System.Linq;
using System.Reflection;
...
// Key : type + field name, say Tuple.Create(typeof(Thing1), "Name")
// Value : corresponding value, say "Thing 1";
static Dictionary<Tuple<Type, string>, string> s_Dictionary = AppDomain
.CurrentDomain
.GetAssemblies() // I've taken all assemblies; you may want to add Where here
.SelectMany(asm => asm.GetTypes())
.Where(t => t.IsAbstract && t.IsSealed) // All static types, you may want to add Where
.SelectMany(t => t
.GetFields() // All constant string fields
.Where(f => f.FieldType == typeof(string))
.Where(f => f.IsPublic && f.IsStatic)
.Where(f => f.IsLiteral && !f.IsInitOnly) // constants only
.Select(f => new {
key = Tuple.Create(t, f.Name),
value = f.GetValue(null)
}))
.ToDictionary(item => item.key, item => item.value?.ToString());
If you want to scan not all loaded but just one (executing) assembly
static Dictionary<Tuple<Type, string>, string> s_Dictionary = Assembly
.GetExecutingAssembly()
.GetTypes()
.Where(t => t.IsAbstract && t.IsSealed)
...
Now you can wrap the dictionary, say
public static string ReadConstant<T>(string name = null) {
if (string.IsNullOrEmpty(name))
name = "Name";
if (s_Dictionary.TryGetValue(Tuple.Create(typeof(T), name), out string value))
return value;
else
return null; // Or throw exception
}
Usage
string name1 = ReadConstant<Thing1>();
You could use non static classes and add those to a dictionary having a Type key. But you would have to use read-only properties.
public interface IConstants
{
string Name { get; }
double InitialHealth { get; }
public int? MaxTries { get; }
}
public class Thing1 : IConstants
{
public string Name => "Thing 1";
public double InitialHealth => 100.0;
public int? MaxTries => null;
}
public class Thing2 : IConstants
{
public string Name => "Thing 2";
public double InitialHealth => 80.0;
public int? MaxTries => 10;
}
Initialize the dictionary:
public static readonly Dictionary<Type, IConstants> Constants =
new Dictionary<Type, IConstants> {
[typeof(Thing1)] = new Thing1(),
[typeof(Thing2)] = new Thing2(),
};
The Create function:
public void Create<T>()
{
Type key = typeof(T);
var foo = new Foo(key.Name);
IConstants constants = Constants[key];
foo.InitialHealth = constants.InitialHealth;
if (constants.MaxTries is int maxTries) { // Only true if MaxTries.HasValue.
// Converts to int at the same time.
foo.Add(maxTries);
}
}
Instead of a static classes with constants. You can create a class with properties and static instances with the desired values.
public class Thing
{
private Thing(string name, string something, bool hasValue, string value)
{
Name = name;
Something = something;
HasValue = hasValue;
Value = value;
}
public string Name { get; }
public string Something{ get; }
public bool HasValue { get; }
public string Value{ get; }
public static Thing Thing1 { get; } = new Thing("Thing1", "Something1", true, "Value1");
public static Thing Thing2 { get; } = new Thing("Thing2", "Something2", false, null);
}
And then your method would just take that class.
public void Create(Thing t)
{
var foo = new Foo(t.Name);
foo.Prop = t.Something;
if (t.HasValue)
foo.Add(t.Value);
}
Then you'd call it with either
Create(Thing.Thing1);
or
Create(Thing.Thing2);
After some reflection I came up with another solution. Why select the constants by type? It is much easier if we use the same type to store the different sets of constants.
public class Constants
{
public string Name { get; set; }
public double Health { get; set; }
public int? MaxTries { get; set; }
}
We then identify the sets through an enum:
public enum SetType
{
Set1, // Please use speaking names in a real implementation!
Set2,
Set3
}
We define the values of the constants while creating the dictionary of constants sets:
public static readonly Dictionary<SetType, Constants> ConstantSets =
new Dictionary<SetType, Constants> {
[SetType.Set1] = new Constants { Name = "Set 1", Health = 100, MaxTries = null },
[SetType.Set2] = new Constants { Name = "Set 2", Health = 80, MaxTries = 5 },
...
};
The Create method becomes
public void Create(SetType set)
{
var constants = ConstantSets[set];
var foo = new Foo(constants.Name) {
Health = constants.Health
};
if (constants.MaxTries is int maxTries) {
foo.Add(maxTries);
}
}
No generics, no reflection, no fancy stuff required.
Hey guys I want to achieve something like this
class Program
{
static void Main(string[] args)
{
Responsible responsible = new Responsible()
{
//I want here to populate with PopulatePerson the base members
Phone = "93827382",
Company = "Google"
};
}
public Person PopulatePerson(string pName, string pLastName)
{
Person person = new Person();
person.Name = pName;
person.LastName = pLastName;
return person;
}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
}
public class Responsible : Person
{
public string Phone { get; set; }
public string Company { get; set; }
}
The case is more complex with database queries and stuff but basically this is what I need
I could use a member called Person in Responsible and do Person = PopulatePerson("Dan", "Johns") but since I'm inheriting I find it kinda redundant
What about something like this. I created a generic (static) factory method for Person that is reusable across all types that inherit from Person.
class Program
{
static void Main(string[] args)
{
//Responsible responsible = new Responsible()
//{
// //I want here to populate with PopulatePerson the base members
// Phone = "93827382",
// Company = "Google"
//};
var responsible = Responsible.Populate("Glenn", "Fake", "93827382", "Google");
//responsible
}
// NO LONGER NEEDED
// ============================
//public Person PopulatePerson(string pName, string pLastName)
//{
// Person person = new Person();
// person.Name = pName;
// person.LastName = pLastName;
// return person;
//}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
public static TPerson Populate<TPerson>(string name, string lastname) where TPerson : Person, new()
{
TPerson person = new TPerson();
person.Name = name;
person.LastName = lastname;
return person;
}
}
public class Responsible : Person
{
public static Responsible Populate(string name, string lastname, string phone, string company)
{
var p = Responsible.Populate<Responsible>(name, lastname);
p.Phone = phone;
p.Company = company;
return p;
}
public string Phone { get; set; }
public string Company { get; set; }
}
Not sure if it makes sense your real scenario but you could change PopulatePerson to accept a Person object as an input parameter instead of internally creating a new one. Then you could pass your new Responsible object to it and afterwards set Phone and Company.
Edit: Like this
class Program
{
static void Main(string[] args)
{
Responsible responsible = new Responsible();
PopulatePerson(responsible, "first", "last");
responsible.Phone = "93827382";
responsible.Company = "Google";
}
public static void PopulatePerson(Person person, string pName, string pLastName)
{
person.Name = pName;
person.LastName = pLastName;
}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
}
public class Responsible : Person
{
public string Phone { get; set; }
public string Company { get; set; }
}
I am beginner in programming and I want to ask you probably the easiest question.
I did something like this:
class person
{
private string name;
public string surname;
private int year;
}
class student : person
{
}
class Program
{
static void Main(string[] args)
{
List<student> list = new List<student>();
list.Add(new student()
{
surname = "jordan"
// name ... ???
// year .. ?
});
}
}
How can I correctly use get and set if I have private field or how can I assign a value to name or year?
You can set private property in constructor like this:
public class person
{
private string name { get; set; };
public string surname { get; set; };
private int year { get; set; };
public person(string name, int year)
{
this.name = name;
this.year = year;
}
}
public class student : person
{
public student(string name, int year) : base (name, year) { };
}
and use can be:
list.Add(new student("name", 45)
{
surname = "jordan"
});
(Note the use of Upper case for classes and properties, lower case reserved for fields and local variables).
Declare as public properties like so:
class Person
{
public string Surname {get; set;}
}
Usage:
new Person{
Surname = "jordan"
};
Or with private setters, and set in constructor.
class Person
{
public Person(string surname)
{
Surname = surname;
}
public string Surname {get; private set;}
}
Usage:
new Person("jordan");
Or private fields, also set in constructor (same usage).
class Person
{
private string surname;
public Person(string surname)
{
this.surname = surname;
}
public string Surname {get{return surname;}}
}
Even if the fields are private you can provide public properties. You should do that anyway since the fields should not be accessible from outside, all the more if they are just backing fields for properties.
class person
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string surname;
public string Surname
{
get { return surname; }
set { surname = value; }
}
private int year;
public int Year
{
get { return year; }
private set { year = value; }
}
}
Now the fields are private and you can change the access modifiers of the properties according to your needs. You can even make the setter private as shown in the Year property.
List<Person> list = new List<Person>();
list.Add(new Person()
{
Name = "Michael",
Surname = "jordan",
});
Now you cannot modify the Year from outside since it's private. You could provide an appropriate constructor to initialize it.
I am building some tiny lib, and I have run into a problem.
I want to provide a two-way solution, for example:
How can I accomplish this?
I am getting exception thrown, because it expects something... Any example that will do is welcomed :) Thanks!
EDIT: I am executing something, initially my code is similar to this one:
System.IO.DriveInfo d = new System.IO.DriveInfo("C:");
I want to achieve with my class the following:
Driver d = new Driver();
d.DriverLetter = "C:";
And still get the same results, I use ManagementObjectSearch, ManagementObjectCollection and some other System.Management classes.
You need to provide both constructors:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
// Paramterless constructor - for new Person();
// All properties get their default values (string="" and int=0)
public Person () { }
// Parameterized constructor - for new Person("Joe", 16, "USA");
public Person (string name, int age, string country)
{
Name = name;
Age = age;
Country = country;
}
}
If you define a parameterized constructor, the default parameterless constructor is not included for you. Therefore you need to include it yourself.
From MSDN 10.10.4 Default constructors:
If a class contains no instance constructor declarations, a default instance constructor is automatically provided.
You have to define a constructor that takes those three arguments:
public class Person
{
public Person(string name, string age, string country)
{
this.Name = name;
this.Age = age;
this.Country = country;
}
}
This way, you can assign the values to the properties when the class is constructed. You can have more than one constructor for a class taking different parameters and you can have one constructor call another constructor with : this() syntax:
public class Person
{
public Person()
: this(string.Empty, string.Empty, string.Empty)
{
}
public Person(string name, string age, string country)
{
this.Name = name;
this.Age = age;
this.Country = country;
}
}
Here the "empty" constructor will call the other constructor and set all properties to empty strings.
Try this:
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public Person()
{
}
public Person(string name, int age, string country)
{
Name = name;
Age = age;
Country = country;
}
}
class Test
{
static void Main(string[] args)
{
var person1 = new Person();
person1.Name = "Joe";
person1.Age = 2;
person1.Country = "USA";
var person2 = new Person("John", 4, "USA");
}
}
The .NET Framework will implicitly provide a default/parameterless constructor if you don't define a constructor. If you define a parameterized constructor, though, you need to explicitly define a default constructor too.
You probably missing your Age property type as int or string.
class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string Country { get; set; }
public Person()
{
}
public Person(string name, int age, string country)
{
this.Name = name;
this.Age = age;
this.Country = country;
}
}
class Program
{
static void Main(string[] args)
{
Person p1 = new Person("Erik", 16, "United States");
Person p2 = new Person();
p2.Name = "Erik";
p2.Age = 16;
p2.Country = "United States";
}
}
EDIT: Also you need parameterless constructor for also.