So, I need to go through my code base and remove all the public setters and change them to private for immutable properties.
I know this will make it harder for me to set the values an I can do that through a constructor. Are there any other ways for me to set the value besides through a constructor?
The point is to limit the access on changing the value.
private string _value;
public SetValue(string value)
{
_value = value;
}
or
ctrl+. on property to encapsulate field
There are several methods that I use to create immutable properties in C#, when I also need to set that property outside of the constructor.
The first scenario is to throw an exception if the object is modified after being set
private object _myProperty;
public object MyProperty
{
public get { return _myProperty; }
public set
{
if(_myProperty == null) { _myProperty = value; }
else { throw new InvalidOperationException("MyProperty can't be changed onece set"); }
}
}
This method doesn't prevent errors before runtime but it can help you catch yourself when you're doing silly things.
Another method is to hide setters using an interface. By explicitly implementing an interface you can hide a property or method from a user unless they cast your class to that specific interface. This doesn't actually make your property immutable, but it helps protect properties from unintentional modification.
public interface MyInterface
{
object MyProperty { get; }
}
public interface MyInterfaceProtected
{
object MyProperty { set; }
}
public class MyClass : MyInterFace, MyInterfaceProtected
{
private object _myProperty;
public object MyProperty { get {return _myProperty;} }
object MyInterfaceProtected.MyProperty
{
set { _myProperty = value; }
}
}
It seems you are talking about C# 6 { get; }. Those properties are settable only from the constructor.
If you will define your property as { get; private set; } you will be able to set it from this class or in derived classes.
Related
My Custom Sitecore control inherits from Sitecore.Web.UI.HtmlControls.Control. This Class defines the Property Value as follows:
public virtual string Value {
get {
return this.GetViewStateString("Value");
}
set {
if (!(value != this.Value))
return;
this.SetViewStateString("Value", value);
}
}
My custom class is defined as follows:
public class ClientProfileSelector : Sitecore.Web.UI.HtmlControls.Control, IContentField {
...
public override string Value {
get {
return this.MyOwnValue;
}
set {
if (!(value != this.MyOwnValue))
return;
this.MyOwnValue = value;
}
}
...
}
The code of the entire class is available here.
My class is automatically instantiated by Sitecore, but I know it is running because I can step into other methods defined therein. For example the method GetValue() in my custom class calls the field Value like so:
public string GetValue() {
return string.IsNullOrEmpty(CalculatedValue) ? CalculatedValue : Value;
}
but when I step over it after adding breakpoints in both my definition and the base class' one, the execution stops in the base class.
What am I doing wrong?
I get the exception:
AmbiguousMatchException: ambiguous match found
when opening my Window and the XAML gets parsed. I have a base ViewModel class. It has a property for the SelectedItem property of a DataGrid
public class BaseViewModel<T> : ViewModel, INotifyPropertyChanged where T : MyClass
{
protected T _selectedItem;
public T SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
}
In my inherited ViewModel I override that property which produces the exception
public new MyInheritedClass SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
//Do other stuff
}
}
So how to use the overrided property and not get an exception?
Why are you redefining the property in the derived class? The type argument of the derived class should specify the type of the property:
public class MyInheritedClass : BaseViewModel<MyClass>
{
//no need to define a new SelectedItem property...
}
In the above sample code MyInheritedClass already has a SelectedItem property of type MyClass. It is already defined in the base class. You don't need to create a new one.
If the property needs to do something special in the derived class, you should define the property as virtual in the base class:
public virtual T SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
}
}
...and override it in the derived class:
public override MyClass SelectedItem
{
get
{
return _selectedItem;
}
set
{
_selectedItem = value;
OnPropertyChanged();
//Do other stuff
}
}
This happens, if you define a Property (or the accessor of a Dependency property) which already exists in the base class. Because then you make it ambigious. Either you have to override (Topic: virtual) or new (hide) it. Otherwise the reflection happenings in WPF will deal with ambiguity.
Example:
public partial class My : UserControl
{
// this will make the ambiguity with the existing trigges-DP legacy accessor
public int Triggers {get;set;}
// this will not make ambiguities, because it hides the original.
// however it may cause other problems
public new object Background {get;set; }
// also OK, but needs justification as well.
public override object ExistingVirtualProperty {get;set; }
...
I recently wrote two classes and an interface as a way to implement the answer to this question of mine.
The first class is the Notifier generic class:
public interface INotifier { }
public class Notifier<T> : Observable,INotifier where T:new()
{
public Notifier()
{
V = new T();
}
private T _ValueBacker;
public T V
{
get { return _ValueBacker; }
set
{
_ValueBacker = value;
OnPropertyChanged(() => V);
}
}
}
The Observable base class here is just a class that implements INotifyPropertyChanged and defines an OnPropertyChanged method.
Thanks to that class, I can now define a Silverlight/WPF ViewModel like this:
public class Person : ViewModelBase
{
Notifier<string> Name {get;set;}
Notifier<string> Surname {get;set;}
Notifier<int> Age {get;set;}
}
instead of:
public class Person : Observable
{
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
_Name=value;
OnPropertyChanger(()=>Name);
}
}
privaate string _Surname;
public string Surname
{
get
{
return _Surname;
}
set
{
_Surname=value;
OnPropertyChanger(()=>Surname);
}
}
private int _Age;
public int Age
{
get
{
return _Age;
}
set
{
_Age=value;
OnPropertyChanger(()=>Age);
}
}
}
As you can see, the new code is much more concise and much less coding-error (or typo) prone. All I have to do in my XAML is to bind to "MyPerson.V" instead of "MyPerson". However, since there aren't any ways to implement initializers for autoproperties, I had to initialize every property in the constructor. In some cases, I skipped the initializers and that led to some runtime errors. So, to take care of that, in the constructor of the ViewModelBase class, I added this loop:
public ViewModelBase()
{
foreach(var notifierProperty in this.GetType().GetProperties().Where(c=>c.PropertyType.GetInterfaces().Any(d=>d==typeof(INotifier))))
{
notifierProperty.SetValue(this, notifierProperty.PropertyType.GetConstructor(System.Type.EmptyTypes).Invoke(null), null);
}
}
What this does is, whenever you instantiate a ViewModelBase derived class, the constructor loops through the properties, and invokes the constructor for each Notifier type property.
Is this evil? Will using reflection this way come back to haunt me in the future? Are there any performance hits I should be aware of?
I think that's fine. I have some bits of information to add:
You can create types with trivial constructors by calling Activator.Create(myType), which means you don't have to fetch a constructor.
I believe at least for Silverlight, all properties initialized with your hack need to be public.
There is a library called ReactiveProperty, that defines a class ReactiveProperty<T> very similar to your Notifier<T>.
You will bind against it's Value property:
public class ReactiveProperty<T> : IObservable<T>, IDisposable, INotifyPropertyChanged, IReactiveProperty, INotifyDataErrorInfo
{
public T Value
{
get { return latestValue; }
set { anotherTrigger.OnNext(value); }
}
// ...
}
The call in the setter eventually leads to the respective call to INotifyPropertyChanged.PropertyChanged.
ReactiveProperty<T> also is an observable in the sense of reactive extensions, on which the library depends. Other than that, the author basically does what you do, but without the initialization hack in the constructor.
Say I have a class
class Object
{
Vector2 positon;
}
This position is editable in the propert grid, how would I be able to set this as not browasable / read only in a class that inherits from object. I know the [Browsable(false)] and [ReadOnly(true)] tags but this will set the it for all Objects, which I do not desire.
Declare position property as virtual and override it on derived types.
public class Class1
{
public virtual string Lol { get; set; }
}
class Class1Impl1 : Class1
{
[Browsable(false)]
[ReadOnly(false)]
public override string Lol
{
get
{
return base.Lol;
}
set
{
base.Lol = value;
}
}
}
class Class1Impl2 : Class1
{
[Browsable(true)]
[ReadOnly(true)]
public override string Lol
{
get
{
return base.Lol;
}
set
{
base.Lol = value;
}
}
}
Doing it at runtime is a different question, IsBrowsable and IsReadOnly are readonly properties. You should google to know if there is posible to change the instances of this attributes at runtime, which I think is not.
I don't think it's possible to change the browseable attribute at runtime (and I don't understand the point of doing that), but you can have a method check your conditions and allow/disallow writing of the property. If that's good enough, I'll be glad to mock something up if you want.
EDIT:
class SomeClass
{
private Object _foo;
private Object _bar;
public Object Foo
{
get
{
return _foo;
}
set
{
if (_bar != _foo) // replace with your test
{
_foo = value;
}
}
}
}
I was wondering if it is possible to change the type of an instance of a derived class in it's base class to another derived class from the same base . following I will try to explain it in a code .
public class ValueTypeClass
{
private string _Note;
private String _Name;
private nodeClass refrenceNode ;
//...
}
public class refrenceDBClass : valuetypeclass
{
//...
}
public class refrenceFileClass : valuetypeclass
{
//...
}
now each time the refrenceNode is changed I want to change the type of the instance based on the refrenceNode properties
Edit 1 :
Now I'm doing this by having another class which keeps the detail of refrencedbclass and refrencefileclass and everytime the refrencenode is changed I'm creating a new instance .
public class ValueTypeClass
{
private string _Note;
private String _Name;
private nodeClass refrenceNode ;
private detailClass detailInfo ;
//...
}
public class detailClass
{
//...
}
public class refrenceDBClass : detailClass
{
//...
}
public class refrenceFileClass : detailClass
{
//...
}
In C#, an instance never changes its type.
I don't understand the problem you want to solve with this, but I assume that you should aggregate this type you want to change, and create a new instance if some value changes. Like the strategy pattern, for instance.
You can not change the type of a managed .NET object. If you were encapsulating the object (in a wrapper - for example refrenceNode) you could swap the reference, but that is about it.
In some (limited) cases, you might be able to serialize/deserialize an encapsulated instance, changing the type in the process (only works for contract-based serializers, with compatible contracts; very unlikely). You certainly can't change the type of the current instance.
Re the edit; again, you can't change the type of how you expose the details, but with some casting you could make it work; vaguely, something like:
public class ValueTypeClass
{
private string _Note;
private String _Name;
private nodeClass refrenceNode;
public nodeClass ReferenceNode {
get {return refrenceNode;}
set {
if(refrenceNode == value) return; // nop
refrenceNode = value;
BuildDetailInfo();
}
}
private detailClass detailInfo;
public detailClass DetailInfo {get {return detailInfo;}}
private void BuildDetailInfo() {
// TODO: decide on the appropriate type (based on refrenceNode)
// and recreate detailInfo
}
}
It sounds like you should also be making use of polymorphism. If you are doing data-binding there are some other things you can do (with considerable effort) to make this more friendly, but it won't affect regular code.