I'll show a problem by example. There is a base class with fluent interface:
class FluentPerson
{
private string _FirstName = String.Empty;
private string _LastName = String.Empty;
public FluentPerson WithFirstName(string firstName)
{
_FirstName = firstName;
return this;
}
public FluentPerson WithLastName(string lastName)
{
_LastName = lastName;
return this;
}
public override string ToString()
{
return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
}
}
and a child class:
class FluentCustomer : FluentPerson
{
private long _Id;
private string _AccountNumber = String.Empty;
public FluentCustomer WithAccountNumber(string accountNumber)
{
_AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(long id)
{
_Id = id;
return this;
}
public override string ToString()
{
return base.ToString() + String.Format(" account number: {0} id: {1}", _AccountNumber, _Id);
}
}
The problem is that when you call customer.WithAccountNumber("000").WithFirstName("John").WithLastName("Smith") you can't add .WithId(123) in the end because return type of the WithLastName() method is FluentPerson (not FluentCustomer).
How this problem usually solved?
Try to use some Extension methods.
static class FluentManager
{
public static T WithFirstName<T>(this T person, string firstName) where T : FluentPerson
{
person.FirstName = firstName;
return person;
}
public static T WithId<T>(this T customer, long id) where T : FluentCustomer
{
customer.ID = id;
return customer;
}
}
class FluentPerson
{
public string FirstName { private get; set; }
public string LastName { private get; set; }
public override string ToString()
{
return string.Format("First name: {0} last name: {1}", FirstName, LastName);
}
}
class FluentCustomer : FluentPerson
{
public long ID { private get; set; }
public long AccountNumber { private get; set; }
public override string ToString()
{
return base.ToString() + string.Format(" account number: {0} id: {1}", AccountNumber, ID);
}
}
after you can use like
new FluentCustomer().WithId(22).WithFirstName("dfd").WithId(32);
You can use generics to achieve that.
public class FluentPerson<T>
where T : FluentPerson<T>
{
public T WithFirstName(string firstName)
{
// ...
return (T)this;
}
public T WithLastName(string lastName)
{
// ...
return (T)this;
}
}
public class FluentCustomer : FluentPerson<FluentCustomer>
{
public FluentCustomer WithAccountNumber(string accountNumber)
{
// ...
return this;
}
}
And now:
var customer = new FluentCustomer()
.WithAccountNumber("123")
.WithFirstName("Abc")
.WithLastName("Def")
.ToString();
A solution where you need fluent interface, inheritance and also some generics...
Anyhow as I stated before: this is the only option if you want to use inheritance and access also protected members...
public class GridEx<TC, T> where TC : GridEx<TC, T>
{
public TC Build(T type)
{
return (TC) this;
}
}
public class GridExEx : GridEx<GridExEx, int>
{
}
class Program
{
static void Main(string[] args)
{
new GridExEx().Build(1);
}
}
Logically you need to configure stuff from most specific (customer) to least specific (person) or otherwise it is even hard to read it despite the fluent interface. Following this rule in most cases you won't need get into trouble. If however for any reason you still need to mix it you can use intermediate emphasizing statements like
static class Customers
{
public static Customer AsCustomer(this Person person)
{
return (Customer)person;
}
}
customer.WIthLastName("Bob").AsCustomer().WithId(10);
public class FluentPerson
{
private string _FirstName = String.Empty;
private string _LastName = String.Empty;
public FluentPerson WithFirstName(string firstName)
{
_FirstName = firstName;
return this;
}
public FluentPerson WithLastName(string lastName)
{
_LastName = lastName;
return this;
}
public override string ToString()
{
return String.Format("First name: {0} last name: {1}", _FirstName, _LastName);
}
}
public class FluentCustomer
{
private string _AccountNumber = String.Empty;
private string _id = String.Empty;
FluentPerson objPers=new FluentPerson();
public FluentCustomer WithAccountNumber(string accountNumber)
{
_AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(string id)
{
_id = id;
return this;
}
public FluentCustomer WithFirstName(string firstName)
{
objPers.WithFirstName(firstName);
return this;
}
public FluentCustomer WithLastName(string lastName)
{
objPers.WithLastName(lastName);
return this;
}
public override string ToString()
{
return objPers.ToString() + String.Format(" account number: {0}", _AccountNumber);
}
}
And invoke it using
var ss = new FluentCustomer().WithAccountNumber("111").WithFirstName("ram").WithLastName("v").WithId("444").ToString();
Is a fluent interface really the best call here, or would an initializer be better?
var p = new Person{
LastName = "Smith",
FirstName = "John"
};
var c = new Customer{
LastName = "Smith",
FirstName = "John",
AccountNumber = "000",
ID = "123"
};
Unlike a fluent interface, this works fine without inherited methods giving back the base class and messing up the chain. When you inherit a property, the caller really shouldn't care whether FirstName was first implemented in Person or Customer or Object.
I find this more readable as well, whether on one line or multiple, and you don't have to go through the trouble of providing fluent self-decorating functions that correspond with each property.
I know this is now an old question, but I wanted to share my thoughts about this with you.
What about separating fluency, which is a kind of mechanism, and your classes, when you can ? This would leave your classes pure.
What about something like this ?
The classes
public class Person
{
public string FirstName { get; set; }
public string LastName {get; set;}
public override string ToString()
{
return $"First name: {FirstName} last name: {LastName}";
}
}
public class Customer : Person
{
public string AccountNumber { get; set; }
public long Id { get; set; }
public override string ToString()
{
return base.ToString() + $" account number: {AccountNumber} id: {Id}");
}
}
A class that adds some fluent mechanism
public class FluentCustomer
{
private Customer Customer { get; }
public FluentCustomer() : this(new Customer())
{
}
private FluentCustomer(Customer customer)
{
Customer = customer;
}
public FluentCustomer WithAccountNumber(string accountNumber)
{
Customer.AccountNumber = accountNumber;
return this;
}
public FluentCustomer WithId(long id)
{
Customer.Id = id;
return this;
}
public FluentCustomer WithFirstName(string firstName)
{
Customer.FirstName = firstName;
return this;
}
public FluentCustomer WithLastName(string lastName)
{
Customer.LastName = lastName;
return this;
}
public static implicit operator Customer(FluentCustomer fc)
{
return fc.Customer;
}
public static implicit operator FluentCustomer(Customer customer)
{
return new FluentCustomer(customer);
}
}
An extension method to switch to fluent mode
public static class CustomerExtensions
{
public static FluentCustomer Fluent(this Customer customer)
{
return customer;
}
}
The same example as in question
Customer customer = new Customer().Fluent()
.WithAccountNumber("000")
.WithFirstName("John")
.WithLastName("Smith")
.WithId(123);
Related
I have a class named Person
public class Person
{
string name;
int age;
SampleObject(string name, int age)
{
this.name = name;
this.age = age;
}
public override string ToString()
{
string s = age.ToString();
return "Person: " + name + " " + s;
}
}
I have overridden the ToString() to return the name of the person.
I am using the class in another class:
public class MyClass
{
public int Id {get;set;}
public Person person {get;set;}
}
Now, I want to access the class as
MyClass my = new MyClass();
I want that when I execute my.person, it should return the ToString() value of the person class without explicitly calling the my.person.ToString()
Is it possible and if possible, how can I make this happen.
Thanks
You can create another readonly property
public string PersonName { get {return this.person.ToString();} }
Or add checking for possible null
public string PersonName
{
get
{
return (this.person == null) ? String.Empty : this.person.ToString();
}
}
Based on your comment about setting Name of person by same property
I think approach with separated/specific property will be more maintainable
public string PersonName
{
get
{
return (this.person == null) ? String.Empty : this.person.ToString();
}
set
{
if(this.person == null)
{
this.person = new Person(value, 0);
}
else
{
this.person.Name = value;
}
}
}
I don't understand your question very well. but one of solutions to your question is to use implicit cast.
public class Person
{
string name;
int age;
public Person(string name, int age)
{
this.name = name;
this.age = age;
}
public override string ToString()
{
string s = age.ToString();
return "Person: " + name + " " + s;
}
// here
public static implicit operator string(Person d)
{
return d.ToString();
}
}
public class MyClass
{
public int Id { get; set; }
public Person Person { get; set; }
}
static void Main(string[] args)
{
var myclass = new MyClass();
myclass.Person = new Person("test", 12);
// use like this
string name = myclass.Person;
Console.WriteLine(name);
Console.WriteLine("Press any key to continue.");
Console.ReadLine();
}
You can achieve this with operator overload.
public static implicit operator string(Person p)
{
return p.ToString();
}
If you wish you can implement operator overload in MyClass to so it calls person as well.
public static implicit operator string(MyClass my)
{
return my.person;
}
With this you can do something like
string personString = my;
// or my.person if you only implement it for Person
Also you don't need to have a string variable for the age.
Doing the following will work just fine.
return "Person: " + name + " " + age;
I would suggest to use string.Format though.
return string.Format("Person: {0} {1}", name, age);
Just wondering if it's possible to call a method using property attribute. Basically, I want to set state of the entity when any of the public property changes.
Like we have following code
public class Contact : EntityBase
{
[NotifyChange]
public string FirstName { get; set; }
private void ChangeState()
{
EntityState = EntityState.Modified;
}
}
And when we call
var c = new Contact();
c.FirstName = "John";
before (or after) setting value of FirstName, it call EntityState() function.
Any idea?
It would be much simpler if property is rewritten as:
public class Contact : EntityBase
{
private string _firstName;
[NotifyChange]
public string FirstName
{
get
{
return _firstName;
}
set
{
ChangeState();
_firstName = value;
}
}
private void ChangeState()
{
EntityState = EntityState.Modified;
}
}
Try this:
public class Contact : EntityBase
{
private string _firstName;
public string FirstName
{
get {return _firstName}
set
{
_firstName = value;
EntityState(); // maybe here must by ChangeState()
}
}
private void ChangeState()
{
EntityState = EntityState.Modified;
}
}
I have a pretty simple and straightforward question.
What is the standardized way, or the right way, of calling another constructor of a class, along with the base constructor of such class?
I understand that the second example does not work. It just seems hackish to be doing it the third way. So what is the way that the people who designed C# expected users to do this?
For example:
public class Person
{
private int _id;
private string _name;
public Person()
{
_id = 0;
}
public Person(string name)
{
_name = name;
}
}
// Example 1
public class Engineer : Person
{
private int _numOfProblems;
public Engineer() : base()
{
_numOfProblems = 0;
}
public Engineer(string name) : this(), base(name)
{
}
}
// Example 2
public class Engineer : Person
{
private int _numOfProblems;
public Engineer() : base()
{
InitializeEngineer();
}
public Engineer(string name) : base(name)
{
InitializeEngineer();
}
private void InitializeEngineer()
{
_numOfProblems = 0;
}
}
Can't you simplify your approach by using an optional parameter?
public class Person
{
public int Id { get; protected set; }
public string Name { get; protected set; }
public Person(string name = "")
{
Id = 8;
Name = name;
}
}
public class Engineer : Person
{
public int Problems { get; private set; }
public Engineer(string name = "")
: base(name)
{
Problems = 88;
}
}
[TestFixture]
public class EngineerFixture
{
[Test]
public void Ctor_SetsProperties_AsSpecified()
{
var e = new Engineer("bogus");
Assert.AreEqual("bogus", e.Name);
Assert.AreEqual(88, e.Problems);
Assert.AreEqual(8, e.Id);
}
}
I have class Person, two child classes Staff and Student, interface IPerson. Also I have a class Database and class Gateway. Class Database has
private string name = "username";
and method
public void getName() {return id;}
Both Staff and Student have getName() methods. I need to create request getName() from student and staff classes to database through gateway. Class Gateway has to check if method getName() was requested by Staff (then return id) or Student (then return "Go away!").
Can anyone please help me with that. I was thinking about using Gateway as an interface of Database class, but because I am only trying to learn C#, I don't really know how to do that. Or maybe there's a better way of doing this... Please help
Thanks
here's some code:
public class Staff : Person
{
public Staff() {}
public Staff(string id): base(id) {}
public override string getName()
{
throw new NotImplementedException();
}
public override void Update(object o)
{
Console.WriteLine(id + " notified that {1}", id, o.ToString());
}
public override void UpdateMessage(object p)
{
Console.WriteLine(id + " notified about new message in chat: {1}", id, p.ToString());
}
}
public class Student : Person
{
public Student() {}
public Student(string id): base(id) {}
public override string getName()
{
throw new NotImplementedException();
}
public override void Update(object o)
{
Console.WriteLine(id +" notified that {1}", id, o.ToString());
}
public override void UpdateMessage(object p)
{
Console.WriteLine("Message for " + id + " {1}", id, p.ToString());
}
}
public abstract class Person : IPerson
{
public string id;
public Person() { }
public abstract string getName();
public Person(string i) { this.id = i; }
public abstract void Update(Object o);
public abstract void UpdateMessage(Object p);
}
public interface IPerson
{
void Update(Object o);
void UpdateMessage(Object p);
string getName();
}
class database
{
public string username = "username";
private string name = "user details";
private string grade = "user grade";
public string getName(Object o)
{
if (o is Staff) { return name; }
else { return "Go away!"; }
}
public string getgrade() { return grade; }
}
public class Gateway
{
public void DoSomethingWithPerson(IPerson person)
{
string iD = person.getName();
if (person is Student)
{
return "go away!";
}
else if (person is Staff)
{
return name;
}
}
}
This is a somewhat convoluted question. So, first off, I'd like to point out a few style issues with your C#.
Your database class is lowercase while the rest are cased consistently. Some methods are inconsistent (for example, you use idiomatic PascalCase for some methods, and camelCase or lowercase for others).
IPerson actually has no purpose here because you can pass instances of Staff and Student around as a Person and use everything in basically the same way as now. In most cases, you'll want to choose either an interface or an abstract base class, not both.
C# has a notion of "properties", which is basically a convenient syntax for getters and setters. This is preferred to public fields (as in public string username in your database class or your public string id in Person) because it allows you to keep the implementation of the backing field private. The syntax for this is public string username { get; set; } if you just want a default implementation. You can expand this to more complicated things. For example, maybe you want to ensure that the username is trimmed. (1)
Minor nitpick, but typically object with lowercase o is used.
You don't actually have to call .ToString() on objects in string formatting interpolation. (2)
(1)
private string m_username;
public string username {
get { return m_username; }
set { m_username = (value != null ? value.Trim() : value); }
}
(2) These lines are equivalent.
Console.WriteLine(id + " notified that {1}", id, o.ToString());
Console.WriteLine("{0} notified that {1}", id, o);
Now on to the problem. To me, it sounds like you want different behavior for different classes. With the way it's phrased, this sounds like an access/permissions issue. Depending on how your data store is set up (in this case, it looks like constants in the code, but you could easily do some kind of query), you could do something like...
[Flags]
public enum Permission {
None = 0,
GetName = 1
}
public abstract class Person {
/* ... */
public abstract Permission Permissions { get; }
}
public class Staff : Person {
/* ... */
public override Permission Permissions {
get { return Permission.GetName; }
}
}
public class Student : Person {
/* ... */
public override Permission Permissions {
get { return Permission.None; }
}
}
public class Database {
/* ... */
private Dictionary<string, string> NamesDatabase { get; set; }
public string getName(string id) {
// As a consequence of being managed by Gateway, assume that the caller has access
return NamesDatabase[id];
}
}
public class Gateway {
public string DoSomethingWithPerson(Person person, string desiredNamePersonId) {
if (person.Permissions.HasFlag(Permission.GetName)) {
Database db = new Database();
return db.getName(desiredNamePersonId);
}
return "go away!";
}
}
Supposing we have a constructor for Database as such:
public Database() {
NamesDatabase = new Dictionary<string, string>(2);
NamesDatabase["id1"] = "Student Amy";
NamesDatabase["id2"] = "Staff Mary";
}
And a Main as such:
static void Main() {
Gateway gate = new Gateway();
Console.WriteLine("Student id1 looks up Staff id2: {0}", gate.DoSomethingWithPerson(new Student("id1"), "id2"));
Console.WriteLine("Staff id2 looks up Student id1: {0}", gate.DoSomethingWithPerson(new Staff("id2"), "id1"));
Console.ReadLine();
}
The output is:
Student id1 looks up Staff id2: go away!
Staff id2 looks up Student id1: Student Amy
Feel free to ask clarifying questions if any part is unclear or I'm way off the mark in my assessment.
i'm not sure if this is what you need.
static void Main(string[] args)
{
var gateway = new Gateway();
Console.WriteLine(gateway.DoSomethingWithPerson(new Staff(1)));
Console.WriteLine(gateway.DoSomethingWithPerson(new Student(1)));
}
public class Staff : Person
{
public Staff() { }
public Staff(int id) : base(id) { }
public override void Update(object o)
{
Console.WriteLine(ID + " notified that {1}", ID, o);
}
public override void UpdateMessage(object p)
{
Console.WriteLine(ID + " notified about new message in chat: {1}", ID, p);
}
public override string GetName()
{
return DataBase.GetName(ID);
}
}
public class Student : Person
{
public Student() { }
public Student(int id) : base(id) { }
public override void Update(object o)
{
Console.WriteLine(ID + " notified that {1}", ID, o);
}
public override void UpdateMessage(object p)
{
Console.WriteLine("Message for " + ID + " {1}", ID, p);
}
public override string GetName()
{
return "Go Away!";
}
}
public abstract class Person : IPerson
{
public int ID;
protected Person() { DataBase = new DataBase(); }
public abstract string GetName();
protected Person(int i) { ID = i; DataBase = new DataBase(); }
public abstract void Update(Object o);
public abstract void UpdateMessage(Object p);
public DataBase DataBase { get; set; }
}
public interface IPerson
{
void Update(Object o);
void UpdateMessage(Object p);
string GetName();
}
public class DataBase
{
public string USERNAME = "username";
private const string Name = "user details";
private const string Grade = "user grade";
public string GetName(int id)
{
// you should perform get something.
return Name;
}
public string GetGrade() { return Grade; }
}
//maybe call it facade
public class Gateway
{
public string DoSomethingWithPerson(IPerson person)
{
return person.GetName();
}
}
I want to add a DisplayAttribute to the Client entity (from another project), but don't want to pollute my entity with attributes specific to MVC or a UI layer. So I planned to add the DisplayAttribute by applying a metadata class to a view model inheriting from the entity
If I inherit from the Client entity and then try to use the MetadataTypeAttribute to add a display attribute, it doesn't show up in the browser. Does anyone know how I can achieve the separation and the functionality of being able to add metadata to my entities?
The Client entity class:
public class Client
{
private string firstName;
private string lastName;
private string homeTelephone;
private string workTelephone;
private string mobileTelephone;
private string emailAddress;
private string notes;
public Title Title { get; set; }
public string FirstName
{
get { return this.firstName ?? string.Empty; }
set { this.firstName = value; }
}
public string LastName
{
get { return this.lastName ?? string.Empty; }
set { this.lastName = value; }
}
public string FullName
{
get
{
List<string> nameParts = new List<string>();
if (this.Title != Title.None)
{
nameParts.Add(this.Title.ToString());
}
if (this.FirstName.Length > 0)
{
nameParts.Add(this.FirstName.ToString());
}
if (this.LastName.Length > 0)
{
nameParts.Add(this.LastName.ToString());
}
return string.Join(" ", nameParts);
}
}
public Address Address { get; set; }
public string HomeTelephone
{
get { return this.homeTelephone ?? string.Empty; }
set { this.homeTelephone = value; }
}
public string WorkTelephone
{
get { return this.workTelephone ?? string.Empty; }
set { this.workTelephone = value; }
}
public string MobileTelephone
{
get { return this.mobileTelephone ?? string.Empty; }
set { this.mobileTelephone = value; }
}
public string EmailAddress
{
get { return this.emailAddress ?? string.Empty; }
set { this.emailAddress = value; }
}
public string Notes
{
get { return this.notes ?? string.Empty; }
set { this.notes = value; }
}
public Client()
{
this.Address = new Address();
}
}
The ClientViewModel view model class:
[MetadataType(typeof(ClientMetaData))]
public class ClientViewModel : Client
{
internal class ClientMetaData
{
[Display(ResourceType = typeof(ResourceStrings), Name = "Client_FirstName_Label")]
public string FirstName { get; set; }
}
}
I think you have change the typeof parameter to:
[MetadataType(typeof(ClientViewModel.ClientMetaData))]
public class ClientViewModel : Client
{
internal class ClientMetaData
{
[Display(ResourceType = typeof(ResourceStrings), Name = "Client_FirstName_Label")]
public string FirstName { get; set; }
}
}
For .Net Core 6.0 use
[ModelMetadataType(typeof(ClientViewModel.ClientMetaData))]
insead of
[MetadataType(typeof(ClientViewModel.ClientMetaData))]