I have an object model that has a property like this:
public class SomeModel
{
public string SomeString { get; set; }
public void DoSomeWork()
{
....
}
}
I want the DoSomeWork function to execute automatically after the SomeString property changes. I tried this but it's not working:
public string SomeString { get; set { DoSomeWork(); } }
What's the correct syntax?
Use a private field instead, like this ...
public class SomeModel
{
private string someString = "";
public string SomeString {
get { return this.someString; }
set {
this.someString = value;
this.DoSomeWork();
}
}
public void DoSomeWork()
{
....
}
}
You can't do this with automatic properties - you'll have to create a "manual" property backed by a field.
private string _someString;
public string SomeString
{
get { return _someString; }
set
{
_someString = value;
DoSomeWork();
}
}
If you really can't deal with this boilerplate (say you'd have to do this hundreds of times), consider using an AOP framework like PostSharp to implement this on your behalf - you'd just need to declare an automatic property and an attribute to get the binary rewriter to implement the desired scheme.
This will work...
private string _someString;
public string SomeString { get { return _someString; } set { _someString = value; DoSomeWork(); } }
private string _someString;
public string SomeString
{
get
{
return _someString;
}
set
{
DoSomeWork();
_someString = value;
}
}
C# team has introduced the auto-implement properties in C# 3.0. with the logic of minimizing the model making which is backed by an anonymous field created by compiler. this one is used when you don't need to implement any additional logic on a property of an object class. so it just followed as.
public string Name{ get; set;}// auto-implemented property. no additional logic.
if we want to add some logic as you want to add one function. we must be writing a manual property backed by a private field as like below.
private string _Name;
public string Name
{
get {return _Name;}
set {
_Name=value;
DoSomething(); //Additional logic implemented.
}
}
Related
I want a class/record with protected set and public init access restriction?
To my knowledge this even cannot be done by explicitly implementing a "Set" interface like this:
public interface ISetData<T>
{
T Value { get; set; }
}
public class Data : ISetData<bool>
{
bool ISetData<bool>.Value { get => Value; set => Value = value; } // Error The property Value has no setter
public bool Value { get; init; }
}
Downside is, set functionality is public when using the interface. Not good. (for internal components the interface can be made internal, but that's mostly no option)
Given that only derivations of Data should be able to set data after initialization, the only solution I see is to use an backing field for the property, which is annoying.
Which looks like:
public interface ISetData<T>
{
T Value { get; set; }
}
public class Data : ISetData<bool>
{
bool ISetData<bool>.Value { get => Value; set => _value = value; } // Fine
private bool _value;
public bool Value
{
get { return _value; }
init { }
}
}
That seems odd to me. Would it not be better CLR/c# allows to use access modifiers independently of set/init this like:
public class Data
{
public bool Value { get; init; protected set; }
}
I know this would better be addressed by a feature request, but this is not what this post is about.
So what solutions are available for the scenario "public init, but protected set"?
A simple answer is none.
In C# 9.0, you could have either init or protected set, not both.
You could have a separate property that is protected set and then the public property can be based on your protected property. Example below.
using System;
public class Program
{
public static void Main()
{
var example = new Example{Test = "hello world"};
example.PrintProtectedTest();
Console.WriteLine(example.Test);
example.SetProtectedTest("goodbye world");
Console.WriteLine(example.Test);
}
}
class Example
{
public Example()
{
}
protected string ProtectedTest { get; set; }
public string Test
{
get => ProtectedTest;
init => ProtectedTest = value;
}
public void SetProtectedTest(string test)
{
ProtectedTest = test;
}
public void PrintProtectedTest()
{
Console.WriteLine(ProtectedTest);
}
}
You can run the example here https://dotnetfiddle.net/odGwDj
I am total MVC newbie coming from 10 years of webforms. Here is the code I have inherited:
namespace sample.Models
{
public class Pages
{
public int PageID { get; set; }
public string FolderName { get; set; }
}
}
How can I apply a trim function to the "set" portion of this code? Right now it is allowing spaces at the end of foldername and I need to prevent that.
Okay I have incorporated the suggestions however the spaces are still getting saved.
Here are the UI/ vs Database. The UI is trimming properly but the full value with spaces is stored in the table:
You need a backing field:
public class Pages
{
public int PageID { get; set; }
private string _folderName;
public string FolderName
{
get { return _folderName; }
set { _folderName = value.Trim(); }
}
}
In the setter method we use the Trim string's method, which
Removes all leading and trailing white-space characters from the current String object.
For further info regarding this method, please have a look here.
What about this solution:
public class Pages
{
private string _folderName;
public int PageID { get; set; }
public string FolderName
{
get { return _folderName; }
set { _folderName = value?.Trim() ?? string.Empty; }
}
}
You may consider writing a custom extension method to call Trim only if the value of your string is not null:
public static class CustomExtensions
{
public static string TrimIfNotNull(this string value)
{
if (value != null)
{
value = value.Trim();
}
return value;
}
}
And then in your Pages class, something like
private string _folderName;
public string FolderName
{
get { return _folderName.TrimIfNotNull(); }
set { _folderName = value.TrimIfNotNull(); }
}
If you're using C#6, as mentioned by Jacob Krall, you can use the null conditional operator directly and not worry about the extension method:
public string FolderName
{
get { return _folderName; }
set { _folderName = value?.Trim(); }
}
The shorthand syntax for properties is only for when you want to provide a thin layer of abstraction on top of a field. If you want to manipulate the field within the getter or setter, you need to specify the backing field on your own.
namespace sample.Models
{
public class Pages
{
public int PageID { get; set; }
private string folderName;
public string FolderName
{
get { return folderName; }
set { folderName = value.Trim(); }
}
}
}
public class Pages
{
public int PageId { get; set; }
// you need a backing field then you can customize the set and get code
private string folderName;
public string FolderName
{
get { return this.folderName; }
// if the fileName can be set to null you'll want to use ?. or you'll get
// a null reference exception
set { this.folderName = value?.Trim(); }
}
}
See the code below.
//You can filter the entry before saving it into the database.
//About the null issue. You can use this.
if(String.IsNullOrEmpty(txtusername.Text))
{
throw new Exception("Cannot be blank!");
}
//You can filter the entry before saving it into the database
txtpageid.Text = book.PageID.Trim();
txtfoldername.Text = book.FolderName.Trim();
I need to build an attribute that will override the getter and the setter of an property. To be more clear, here is how it works today and how it should work using the attribute (the result should be the same).
Old version:
public class A
{
private Handle _handle;
public String StringProp
{
get {
return _handle.GetProperty(PropId.StringProp);
}
set {
_handle.SetProperty(PropId.StringProp, value);
}
}
public int IntProp
{
get {
return _handle.GetProperty(PropId.IntProp);
}
set {
_handle.SetProperty(PropId.IntProp, value);
}
}
}
New version:
public class A
{
private Handle _handle;
[HandleProperty(PropId.StringProp)]
public String StringProp { get; set; }
[HandleProperty(PropId.IntProp)]
public int IntProp { get; set; }
}
The attribute HandleProperty should known to link the getter and setter to _handle.GetProperty and _handle.SetProperty.
I created two enums and some of the fields in one enum were mapped to another enums fields using attributes. I think you can do something like this...
[AttributeUsage(AttributeTargets.Field)]
public sealed class MapsToAttribute : Attribute
{
private string Text;
public string MapsToText
{
get
{
return Text;
}
}
public MapsToAttribute(string mapsToText)
{
Text = mapsToText;
}
public override string ToString()
{
return Text;
}
}
how can i create a method that get's an object to read only purpose
public class Person
{
public string Name;
}
public void RunMe(Person p)
{
p.Name="XXXX";
}
var p =new Person();
p.Name="YYYY";
RunMe(p);
Console.WriteLine(p.Name);
I am getting XXXX. but i want that the person object will not change it value.
you can use interfaces to restrict the access. It is also better to pass interfaces instead of concrete objects as parameters to methods.
public interface IReadablePerson
{
string Name { get; }
}
public interface IWritablePerson
{
string Name { set; }
}
public class Person : IReadablePerson, IWritablePerson
{
public string Name { get; set; }
}
and then have a method like this
public void RunMe(IReadablePerson p)
{
p.Name = "XXXX"; //compile time error!!!
}
The way to do this is via the get and set accessors, just don't define a set:
public String Name { get; }
This will make a property that you can treat exactly like a normal field for your purposes. Underneath properties are a little more complex using methods to set a backing field which you can read about on msdn
If you need to be able to set the property just once then define the set as private and pass the parameter into the constructor:
public class Person
{
public Person(String name)
{
this.Name = name;
}
public String Name { get; private set; }
}
Classes in C# are reference types, so there's no way to do what you want to do if Person is a class.
You could make it a value type (by making it a struct) in which case, a copy of the object would be passed in, but that may take implications at some other points in your program, so be wary if you do it.
It seems that you want to somehow be able to lock the member. One option would be to make the "set" dependent on another member like this:
public class Name
{
public bool Locked { get; set; }
private string name;
public string Name
{
get { return this.name; }
set
{
if(!this.Locked)
this.name = val;
}
}
}
Edit: Alternate method for making lock permanent.
public class Person
{
private bool locked = false;
public void Lock()
{
this.locked = true;
}
public bool Locked
{
get { return this.locked; }
}
// add same Name member as above
}
Edit: Yet ANOTHER way to lock, using a key.
private object key = null;
public bool Locked
{ get { return this.key != null; } }
public void Lock(object obj)
{
if (this.key == null)
{
this.key = obj;
}
}
public void Unlock(object obj)
{
if (this.key == obj)
{
this.key = null;
}
}
You can throw an exception if you want if trying to unlock with the wrong key object.
The behaviour described after the first setting of the property is this:
private string _name;
public string Name
{
get { return _name; }
set { // no setting }
}
This is NOT A GOOD PRACTICE.
you create unexpected behaviour for properties (if this is a public class).
Any consuming assembly cannot view the body of the get and set methods would expect a set method to behave a sertain way (setting a value).
This kind of behaviour should be put in a seperate set method.
This way you can see if it changed, throw an exception if you want, or return true if it changed.
Then you can still use the property for getting the value.
private bool _locked;
public string Name { get; private set;}
public boolSetName(string value)
{
bool hasChanged = false;
if(!_locked)
{
Name = value;
_locked = true;
hasChanged = true;
}
return hasChanged
}
Let's say I have a POCO with a property as such
public class Person
{
private string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
// DO STUFF;
}
}
}
When the object is being initialized by EF, I only want _firstName to be set and nothing else, only after the object is initialized do I want a set to run the rest // DO STUFF;.
Why don't you simply
Declare the property setter as protected; and
Expose your // DO STUFF behavior as a proper method SetFirstName(string firstName)?
Something like this:
public class Person
{
public string FirstName { get; protected set; }
public string SetFirstName(string value)
{
_firstName = value;
// DO STUFF;
}
}
Much cleaner, don't need to "hack" EF at all.