Context
So after researching a bit about UI toolkit, i decided to use it for my project as i am very used to CSS and i despise the "default/legacy" UI system Unity3D offers.
Unfortunately its on a very early stage of development and they seem to be taking it in a "editor GUI" direction. Regardless i choose it as it made designing the UI, way faster than i could ever do with the usual "Unity3D UI" method of doing things.
Objective
My objective is relatively simple, i want to create a behavior that updates the UI based on some variable while hiding/abstracting this behavior(in other words i want to bind the value of the UI to some integer on a data class).
In the future this will be further complicated due to me slowly migrating everything to a multiplayer context
Main Problem
After hours of searching/reading the documentation, and brute forcing my way into the problem, i managed to reach to a simple solution, which i will abreviate due to me hardcoding some very similar behaviour:
GameObject trackCanvas = GameObject.Find("Canvas");
UIDocument docum= trackCanvas.GetComponent<UIDocument>();
Label foodUI = docum.rootVisualElement.Q<Label>(name: "FoodVar");
if(playerResources!= null){
SerializedObject pR = new SerializedObject(playerResources);
SerializedProperty foodProp = pR.FindProperty("food");
foodUI.BindProperty(foodProp);
}else{
foodUI.Unbind();
}
Pretty simple solution and better yet i saved some thinking time. It all worked like a charm until i try to build it and... I see multiple errors relating to importing UnityEditor which i started removing it(since i pretty much import everything and only on CleanUp i start to see whats necessary or not)
Unfortunately on this very script i couldnt and after rereading the documentation on the fine print(which wasnt so fine...) i read that SerializedObject can't be used in "production/runtime/build" version because it depended on UnityEditor which wouldnt exist on the finalized product.
Which really annoyed me because it was a very eloquent solution.
Suffix
The manual seems to suggest there is ways to go around using UnityEditor namespace. Unfortunately from their very vague tutorial i wasnt able to figure out how it works(im mentioning the tank example which only seems to use unityeditor because they wanted to be able to bind stuff on edit mode, while the binding itself seems to be done through uxml)
I've tried a few things but it all seemed out of context like having some serializedField would magically bind with uxml just because the binding path was the same as variable name
Then i thought well if unity doesnt want me to use editor stuff in runtime mode ill just force it so It shouldnt be that hard to just copy paste some of its class's and then somehow hack it. Unfortunetely Unity not only has a strict proprietary license that doesnt allow you to modify its software in anyway, but some of the annotations, functions, etc... were protected(especially the C stuff that they use)
Then i thought about doing it by hand and i arrived at two options:
Just put food.value = resources.food in some kind of update and hope it doesnt create any kind of issues when i migrate it to a multiplayer context
Or do something more complicated like some kind of delegate i would call that would update the UI, being more efficient in theory due to me only updating whats needed to.
Since im doing an RTS, i think the values will be changing constantly, so im very divided on both. Making me want to stick to the solution that was already done
This is all the more stressful when i hate how the documentation is structured, how difficult it is to go around the source code, and the worse how it feels like the documentation goes in length for behavior that is very similar to CSS
TL;DR:
Is there an alternative to BindProperty() in UI toolkit that doesn't rely on Unity Editor?
You could create a wrapper class to hold your values, which could invoke an event whenever the wrapped value changes.
public interface IProperty<T> : IProperty
{
new event Action<T> ValueChanged;
new T Value { get; }
}
public interface IProperty
{
event Action<object> ValueChanged;
object Value { get; }
}
[Serializable]
public class Property<T> : IProperty<T>
{
public event Action<T> ValueChanged;
event Action<object> IProperty.ValueChanged
{
add => valueChanged += value;
remove => valueChanged -= value;
}
[SerializeField]
private T value;
public T Value
{
get => value;
set
{
if(EqualityComparer<T>.Default.Equals(this.value, value))
{
return;
}
this.value = value;
ValueChanged?.Invoke(value);
valueChanged?.Invoke(value);
}
}
object IProperty.Value => value;
private Action<object> valueChanged;
public Property(T value) => this.value = value;
public static explicit operator Property<T>(T value) => new Property<T>(value);
public static implicit operator T(Property<T> binding) => binding.value;
}
After this you could create custom extension method similar to Unity's own BindProperty which works with this wrapper instead of a SerializedProperty.
public static class RuntimeBindingExtensions
{
private static readonly Dictionary<VisualElement, List<(IProperty property, Action<object> binding)>> propertyBindings = new Dictionary<VisualElement, List<(IProperty property, Action<object> binding)>>();
public static void BindProperty(this TextElement element, IProperty property)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
bindingsList = new List<(IProperty, Action<object>)>();
propertyBindings.Add(element, bindingsList);
}
Action<object> onPropertyValueChanged = OnPropertyValueChanged;
bindingsList.Add((property, onPropertyValueChanged));
property.ValueChanged += onPropertyValueChanged;
OnPropertyValueChanged(property.Value);
void OnPropertyValueChanged(object newValue)
{
element.text = newValue?.ToString() ?? "";
}
}
public static void UnbindProperty(this TextElement element, IProperty property)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
return;
}
for(int i = bindingsList.Count - 1; i >= 0; i--)
{
var propertyBinding = bindingsList[i];
if(propertyBinding.property == property)
{
propertyBinding.property.ValueChanged -= propertyBinding.binding;
bindingsList.RemoveAt(i);
}
}
}
public static void UnbindAllProperties(this TextElement element)
{
if(!propertyBindings.TryGetValue(element, out var bindingsList))
{
return;
}
foreach(var propertyBinding in bindingsList)
{
propertyBinding.property.ValueChanged -= propertyBinding.binding;
}
bindingsList.Clear();
}
}
Usage:
public class PlayerResources
{
public Property<int> food;
}
if(playerResources != null)
{
foodUI.BindProperty(playerResources.food);
}
UPDATE: Added also extension methods for unbinding properties and made BindProperty immediately update the text on the element.
Related
So I was creating a Monopoly console app to explore some design concepts as well as to try to understand Test-Driven Development better.
That being the case, I created unit tests to make sure that all of my classes can be serialized and deserialized properly (because I'm going to need that later and if they can't be I'd rather know that sooner than later so I can avoid rework; doing so has, in fact, helped me catch several flaws in my initial design).
This property is part of a larger Property class. Owner is the player that owns the property.
What I'm trying to achieve here is that when a player mortgages a particular property, the property should be marked as "Mortgaged" and the player should receive half of the purchase price in cash. When they unmortgage the property, they pay the money back. There will be a few other checks that I haven't written yet as well; for example, game rules specify that you're not allowed to mortgage a property while it still has houses on it. I also don't yet check to see if the player has enough money to unmortgage the property, but I plan to add that shortly as that's a trivial rule to implement. That's why I'm using a setter here instead of an auto-generated property.
Here's the problem: this serializes and deserializes without throwing an exception, but if I serialize a mortgaged property it'll add the money a second time when I deserialize it (i.e. deserializing basically has the effect of re-mortgaging the property), so needless to say the unit test fails (which it should given that there's an obvious bug). I suppose that that's not surprising given that that's exactly how I wrote it - when you change its value it'll either mortgage or unmortgage the property.
Here's the code:
[JsonProperty(Order = 1)]
public Player Owner
{
get;
set;
}
private bool _isMortaged = false;
[JsonProperty(Order = 2)]
public bool IsMortgaged
{
get { return _isMortaged; }
set
{
if (!IsOwned)
{
throw new InvalidOperationException("You can't mortgage a property that no one owns");
}
// If we're setting this property to the same thing that it
// already was, log it. You could argue that that would indicate
// a bug (it probably would), but throwing an exception here
// breaks deserialization.
Debug.WriteIf(value == _isMortaged, $"Setting IsMortgaged to the same thing as it was before. Stack trace:{Environment.NewLine}{(new StackTrace()).ToString()}");
// If we're setting this to the same thing that it already was,
// then the setter should have no effect at all.
if (value != _isMortaged)
{
// The player is mortgaging the property
if (value)
{
_isMortaged = true;
Owner.Money += (PurchasePrice / 2);
}
// The player is unmortgaging the property
else
{
_isMortaged = false;
Owner.Money -= (PurchasePrice / 2);
}
}
}
}
Is there an easy way to have a different setter for deserialization, or to tell whether or not I'm deserializing in the setter? (The latter seems like a "hack"). I suppose that there's also the possibility of writing a custom deserializer, which would solve the problem I guess, but I'd much rather avoid that if possible (it doesn't seem like a particularly "clean" way of doing this).
Alternatively, is this just a design flaw?
This is a design flaw; setters shouldn't have side effects beyond the obvious of updating a value (and those that are expected eg. INotifyPropertyChanged)
If you need special behaviour, then either introduce a special setting method, or think of it the other way around:
You're mortgaging/un-mortgaging a property, so you want the owner of that property's balance to update
Instead of having the property update the owner's balance (which it shouldn't concern itself with: Separation of Concerns; you could instead have the owner's balance property be dynamically computed:
public class Property {
public bool IsMortgaged {get;set;}
}
public class Player
{
private List<Property> _properties = new List<Property>();
private double _cash = 0;
public int AvailableMoney =>
_cash + _properties.Where(p => p.IsMortgaged).Select(p => p.MortgageValue).Sum();
}
Now, this will obviously need to be updated to properly match your model, but ideally you want your data to be as dumb as possible; whether a property is mortgaged or not is a simple true/false. It's the balance that is special, and there's no reason not to re-compute it.
This is a violation of the Single Responsibility or Separation of concerns.
The way I would go about this would be to have a private setter on Property.IsMortgaged and use some JSON.NET functionality that exists already to deserialize it.
This would need some new methods on Property and Owner
For Property you would need to add:
public class Property
{
public double Value {get;} = 5000.00
private bool _isMortgaged
public bool SetMortgaged()
{
//Validation for if the property can be mortgaged goes here, return false if fails
if(_isMortgaged == true)
{
return false;
}
_isMortgaged = true;
return true;
}
}
and on the Owner class
public class Owner //or player
{
private double _cash;
public double AvailableCash
{
get {return _cash;}
}
public void MortgageProperty(Property item)
{
if(item.SetMortgaged())
{
_cash += item.Value / 2
}
else
{
//Throw an error or something else to let the user know it failed
}
}
}
This will encapsulate the logic in the respective classes, the Property will know if it can be mortgaged and the Owner takes care of the money.
When using WPF databinding, I obviously can't do something along the lines of MyCollection = new CollectionType<Whatever>( WhateverQuery() ); since the bindings have a reference to the old collection. My workaround so far has been MyCollection.Clear(); followed by a foreach doing MyCollection.Add(item); - which is pretty bad for both performance and aesthetics.
ICollectionView, although pretty neat, doesn't solve the problem either since it's SourceCollection property is read-only; bummer, since that would have been a nice and easy solution.
How are other people handling this problem? It should be mentioned that I'm doing MVVM and thus can't rummage through individual controls bindings. I suppose I could make a wrapper around ObservableCollection sporting a ReplaceSourceCollection() method, but before going that route I'd like to know if there's some other best practice.
EDIT:
For WinForms, I would bind controls against a BindingSource, allowing me to simply update it's DataSource property and call the ResetBindings() method - presto, underlying collection efficiently changed. I would have expected WPF databinding to support a similar scenario out of the box?
Example (pseudo-ish) code: WPF control (ListBox, DataGrid, whatever you fancy) is bound to the Users property. I realize that collections should be read-only to avoid the problems demonstrated by ReloadUsersBad(), but then the bad code for this example obviously wouldn't compile :)
public class UserEditorViewModel
{
public ObservableCollection<UserViewModel> Users { get; set; }
public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ }
public void ReloadUsersBad()
{
// bad: the collection is updated, but the WPF control is bound to the old reference.
Users = new ObservableCollection<User>( LoadUsersFromWhateverSource() );
}
public void ReloadUsersWorksButIsInefficient()
{
// works: collection object is kept, and items are replaced; inefficient, though.
Users.Clear();
foreach(var user in LoadUsersFromWhateverSource())
Users.Add(user);
}
// ...whatever other stuff.
}
If the object MyCollection is of implements INotifyPropertyChanged, you can simply replace the collection.
An example:
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Whatever> _myCollection;
private void NotifyChanged(string property)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
public ObservableCollection<Whatever> MyCollection
{
get
{
return _myCollection;
}
set
{
if (!ReferenceEquals(_myCollection, value))
{
_myCollection = value;
NotifyChanged("MyCollection");
}
}
}
}
With this, when you assign a collection, WPF detects this and everything gets updated.
This is how I'd solve this.
The link below explains how to implement an AddRange method.
http://web.archive.org/web/20150715112054/http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx
It looks like you're stuck with implementing a sub-class that handles this case correctly.
Apparently, certain controls don't support batched collection change notifications. At least they didn't when that article was written. Though now you should have a bit more information if you want to investigate further.
So I've got a whole bunch of options, every different page/tab can have their own local options. We'll have maybe 10-15 pages tabs open tops. I need to implement a way to show the global defaults, weather the all the tabs have consistent values. I'm working on the model/viewmodel portion of a WPF app.
I'd love to find a way that is more elegant since I'm having to cut and past roughly the same code 20+ times and just change property names. Maybe this is the problem Dynamics solve, but right now this feels both wrong and painful.
Here is an example of my current solution:
public class Foo
{
private bool fooVar1;
private bool fooVar2;
//lots of these
private decimal fooVar23;
public Foo()
{
}
public bool FooVar1
{
get;
set;
}
//you get the picture...
}
public class FooMonitor
{
private Foo defaultFoo;
private List<Foo> allFoos;
public FooMonitor(Foo DefaultFoo)
{
defaultFoo = DefaultFoo;
}
public void AddFoo(Foo newFoo)
{
allFoos.Add(newFoo);
}
public void AddFoo(Foo oldFoo)
{
allFoos.Remove(oldFoo);
}
public bool IsFooVar1Consistent
{
get
{
Foo[] tempFoos = allFoos.ToArray();
foreach (Foo tempFoo in tempFoos)
{
if (tempFoo.FooVar1 != defaultFoo.FooVar1) return false;
}
return true;
}
}
}
Or am I approaching this problem entirely incorrectly.
As I'm writing this question (After about 2000 lines of code) I'm thinking of how I read that WPF itself implements Dictionary look ups that crawl up to the parent to see if a Property is present and what the value should be.
Well, for a start you are defining both backing fields which will never be used and automatic properties. This is enough for a simple bool property:
public bool FooVar1 { get; set; }
No need for the private field. This greatly reduces the number of lines in your example.
I'd love to find a way that is more
elegant since I'm having to cut and
past roughly the same code 20+ times
and just change property names.
Code generators exist for exactly this purpose. But if you don't want to go that route, you can shorten your code to this:
return allFoos.All(foo => foo.FooVar1 == defaultFoo.FooVar1);
I'm not quite sure what the question is, but if you're looking for some way to unify the IsFoorVarXConsistent code, you could do it using reflection or by passing in an expression:
public bool IsConsistent(Func<Foo, bool> property)
{
foreach (Foo tempFoo in allFoos)
{
if (property(tempFoo) != property(defaultFoo))
return false;
}
return true;
}
Called like this:
bool is1Consistent = IsConsistent(f => f.FooVar1);
As shown this will only work for boolean properties. To extend it to other types, we can make it generic in the property type. However, in this case we cannot use != to test for inequality because not all types define a != operator. Instead we can use the .Equals method and the ! operator:
public bool IsConsistent<T>(Func<Foo, T> property)
where T : struct
{
foreach (Foo tempFoo in allFoos)
{
if (!property(tempFoo).Equals(property(defaultFoo)))
return false;
}
return true;
}
The where T : struct clause restricts this to value types like int, bool and decimal. In particular it will not work on strings. Removing the where constraint allows it to work on strings and other reference types, but creates the possibility of property(tempFoo) being null, which would cause a NullReferenceException when we called .Equals on it. So if you remove the value types constraint then you will need to add error handling for this scenario.
I find myself writing this code a lot:
private int _operationalPlan;
public int OperationalPlan
{
get
{
return _operationalPlan;
}
set
{
_operationalPlan = value;
RaisePropertyChanged();
}
}
private void RaisePropertyChanged()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs("PlansSelected"));
}
}
I'm wondering whether it might be possible to write an attribute that could be added to the property to automatically raise the event. I.e. something like this:
[RaiseOnSet("ProperyChanged", "PropertyChangedEventArgs", "PlansSelected")]
public int OperationalPlan
{
get
{
return _operationalPlan;
}
set
{
_operationalPlan = value;
RaisePropertyChanged();
}
}
Before I go and try to implement this I was wondering:
Is this facility in the .net framework
Has anyone tried to this facility
If it's possible
If there are any dead ends that I should avoid
To do that, you would need an AOP framework for .NET, like PostSharp or AOP.NET
I you are prepared to use a helper class to wrap the property values you can do this. But that means any client accessing the property will need to unwrap the value.
Another route is to use a helper type, see WPF and WF using (different) DependencyProperty for this. But you don't get automatically implemented properties.
I have a class (Foo) which lazy loads a property named (Bar). What is your preferred way to protect against mistaken use (due to intellisense or inexperienced staff) of the uninitialized backing field?
I can think of 3 options:
class Foo {
// option 1 - Easy to use this.bar by mistake.
string bar;
string Bar {
get {
// logic to lazy load bar
return bar;
}
}
// option 2 - Harder to use this._bar by mistake. It is more obscure.
string _bar2;
string Bar2 {
get {
// logic to lazy load bar2
return _bar2;
}
}
//option 3 - Very hard to use the backing field by mistake.
class BackingFields {
public string bar;
}
BackingFields fields = new BackingFields();
string Bar3 {
get {
// logic to lazy load bar
return fields.bar;
}
}
}
Keep in mind, the only place I want people mucking around with the backing field bar is in setter and getter of the property. Everywhere else in the class they should always use this.Bar
Update
I am currently using the following Lazy implementation (not for all properties with backing fields, but for select ones that require lazy loading, synchronization and notification). It could be extended to support futures as well (force evaluation in a separate thread in a later time)
Note My implementation locks on read, cause it supports an external set.
Also, I would like to mention that I think this is a language limitation which can be overcome in Ruby for example.
You can implement lazy in this way.
x = lazy do
puts "<<< Evaluating lazy value >>>"
"lazy value"
end
puts x
# <<< Evaluating lazy value >>>
# lazy value
How about use of ObsoleteAttribute and #pragma - hard to miss it then!
void Test1()
{
_prop = ""; // warning given
}
public string Prop
{
#pragma warning disable 0618
get { return _prop; }
set { _prop = value; }
#pragma warning restore 0618
}
[Obsolete("This is the backing field for lazy data; do not use!!")]
private string _prop;
void Test2()
{
_prop = ""; // warning given
}
Option 5
Lazy<T>
works quite nicely in several situations, though option 1 should really be just fine for most projects so long as the developers aren't idiots.
Adding [EditorBrowsable(EditorBrowsableState.Never)] to the field won't help if it is private since this logic only kicks in for intellisense generated from metadata rather than the current code (current project and anything done via project references rather than dlls).
Note: Lazy<T> is not thread safe (this is good, there's no point locking if you don't need to) if you require thread safety either use one of the thread safe ones from Joe Duffy or the Parallel Exetensions CTP
I usually go for option 2, as it is easier to spot mistakes later on, although option 1 would pass a code review. Option 3 seems convoluted and whilst it may work, it's not going to be nice code to revisit 6 months down the line whilst trying to refactor/fix a bug/etc.
Option 1, coupled with some education.
Rationale: software is meant to be read more often than written, so optimize for the common case and keep it readable.
Code reviews will catch misuse so just go with the most readable. I dislike attempts to work around bad programmers in code, because 1) they don't work, 2) they make it harder for smart programmers to get their work done, and 3) it addresses the symptom rather than the cause of the problem.
I usually just go for option 1. Because it is a private field I don't think it really an issue, and using something like the wrapper class as in your option 3 only makes code difficult to read and understand.
I would just put a large comment block on the top of the class that would look like that:
/************************************************************
* Note: When updating this class, please take care of using *
* only the accessors to access member data because of *
* ... (state the reasons / your name, so they can ask *
* questions) *
*************************************************************/
Usually, just a note like that should be enough, but if this is the same for all the classes in the project, you might prefer to put it in a simple document that you give to programmers working on the project, and everytime you see code that isn't conform, you point them to the document.
Automatic properties:
public int PropertyName { get; set; }
will prevent access to the backing field. But if you want to put code in there (e.g. for lazy loading on first access) this clearly won't help.
The simplest route is likely to be a helper type which does the lazy loading, and have an private field of that type, with the public property calling to the correct property/method of the helper type.
E.g.
public class Foo {
private class LazyLoader {
private someType theValue;
public someType Value {
get {
// Do lazy load
return theValue;
}
}
}
private LazyLoader theValue;
public someType {
get { return theValue.Value; }
}
}
This has the advantage that the backing field is harder to use than the property.
(Another case of an extra level of indirection to solve problems.)
// option 4
class Foo
{
public int PublicProperty { get; set; }
public int PrivateSetter { get; private set; }
}
C# 3.0 feature, the compiler will generate anonymous private backing fields which can't be accessed by mistake, well unless you use reflection...
EDIT: Lazy instantiation
You can have laziness like this:
// I changed this with respect to ShuggyCoUk's answer (Kudos!)
class LazyEval<T>
{
T value;
Func<T> eval;
public LazyEval(Func<T> eval) { this.eval = eval; }
public T Eval()
{
if (eval == null)
return value;
value = eval();
eval = null;
return value;
}
public static implicit operator T(LazyEval<T> lazy) // maybe explicit
{
return lazy.Eval();
}
public static implicit operator LazyEval<T>(Func<T> eval)
{
return new LazyEval(eval);
}
}
Those implicit conversion make the syntax tidy...
// option 5
class Foo
{
public LazyEval<MyClass> LazyProperty { get; private set; }
public Foo()
{
LazyProperty = () => new MyClass();
}
}
And closures can be used to carry scope:
// option 5
class Foo
{
public int PublicProperty { get; private set; }
public LazyEval<int> LazyProperty { get; private set; }
public Foo()
{
LazyProperty = () => this.PublicProperty;
}
public void DoStuff()
{
var lazy = LazyProperty; // type is inferred as LazyEval`1, no eval
PublicProperty = 7;
int i = lazy; // same as lazy.Eval()
Console.WriteLine(i); // WriteLine(7)
}
}
Currently, I'm in a similar situation.
I have a field which should only be used by its property accessor.
I can't use automatic properties, since I need to perform additional logic when the property is set. (The property is not lazy loaded as well).
Wouldn't it be great if a next version of C# would allow something like this:
public class MyClass
{
public int MyProperty
{
int _backingField;
get
{
return _backingField;
}
set
{
if( _backingField != value )
{
_backingField = value;
// Additional logic
...
}
}
}
}
With such construct, the _backingField variable's scope is limited to the property.
I would like to see a similar language construction in a next version of C# :)
But, I'm afraid this feature will never be implemented:
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=381625
This might be overly simple, but why not abstract all the lazy to a base class
public class LazyFoo{
private string bar;
public string Bar{
get{
// lazy load and return
}
set {
// set
}
}
}
public class Foo : LazyFoo{
// only access the public properties here
}
I could see the argument that it is unnecessary abstraction, but it is the simplest way I can see to eliminate all access to backing fields.
This seems like trying to design-out mistakes that might not happen in the first place, and basically it's worrying about the wrong thing.
I would go with option 1 + comments:
///<summary>use Bar property instead</summary>
string bar;
///<summary>Lazy gets the value of Bar and stores it in bar</summary>
string Bar {
get {
// logic to lazy load bar
return bar;
}
}
If you do get a developer who keeps using the backing variable then I'd worry about their technical competence.
By all means design to make your code easier to maintain, but try to keep it simple - any rule that you make for yourself here is going to be more hassle than it's worth.
And if you're still really worried about it create an FxCop (or whatever you're using) rule to check for this sort of thing.
Option 6:
Makes it very dumb indeed if you use it.
string doNotUseThisBackingField_bar6;
string Bar6 {
get {
// logic to lazy load
return doNotUseThisBackingField_bar6;
}
}
Option 4 (a new solution):
See if the question is really about how to prevent people from using an uninitialized variable then init it with an KNOWN INVALID value.
I would say something like:
string str = "SOMETHING_WRONG_HERE";
Who ever is using 'str' will have some sort of warning.
Otherwise Option 3 if preventing users from using 'str' is more important than readability etc.