How to override a calculated value? - c#

So I have the following snippet of code:
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get
{
return _excessWages ?? CalculateExcessWages();
}
set
{
if (value != CalculateExcessWages())
_excessWages = value;
else
_excessWages = null;
}
}
So basically the behavior I'm trying to implement is if a field is left blank or is assigned a value equal the calculated one use the calculated value, otherwise store the assigned value.
I have a lot of fields that need to support overriding like this. Is this the best way to accomplish this? If not what would you suggest?

I worked on this a bit based mostly on Vlad's suggestion. Turns out you can use a single generic class to abstract this. Here is the end result:
public class Overridable<T>
{
private Func<T> _calculate;
private readonly Func<T, T, bool> _compare;
protected T _t;
public Overridable(Func<T> calculate, Func<T, T, bool> compare)
{
_calculate = calculate;
_compare = compare;
}
public T Value
{
get { return _compare(_t, default(T)) ? _calculate() : _t; }
set { _t = _compare(value, _calculate()) ? default(T) : value; }
}
}
You need to pass in a compare delegate because the type isn't known until you set it in a subclass. So a simple == isn't going to cut it. I went the easy route and used a Func delegate but this could be replaced with a normal delegate if it had to be adapted for .NET 2.0 for some reason.
You'll notice I'm using default(T) instead of null. This works because the default value for a Nullable<T> is null (or more precisely, undefined but it works out to be the same).
This doesn't prevent you from trying to declare an Overridable<T> for a non-nullable type. What you'd wind up with won't through run time errors but it isn't as useful. Trying to set a Overridable<decimal>.Value to null will get you a compiler error. While setting it to default(decimal) will cause it to revert to calculating the value.
I went this route because the properties from this the class I'm using this in needs to populate a serializable object thats eventually transmitted as xml. The schema for the xml includes numeric fields defined as a mixture of integers, decimals and strings.
You then use the Overriddable class like so:
private Overridable<decimal?> _excessWages =
new Overridable<decimal?>(CalculateExcessWages, (x,y) => x == y);
public virtual decimal? ExcessWages
{
get
{
return _excessWages.Value;
}
set
{
_excessWages.Value = value;
}
}
The only problem I ran into with this was that CalculateExcessWages is a non-static method so it can't be used in a field initializer. Since all the properties in my class are non-static I had to initialize all the backing fields in the constructor.

You can make a class wrapper for this.
class OverridableValue<T>
{
public OverridableValue<T>(Func<T> calculator)
{
_calculator = calculator;
}
private Nullable<T> _t;
private Func<T> _calculator;
public T Get()
{
return return _t ?? _calculator();
}
public void Set(T value)
{
_t = (value != _calculator()) ? value : null;
}
}
It's not so syntactically sweet, but at least saves some keystrokes.
Now you can use it like this:
class Foo
{
OverridableValue<decimal> _excessWages =
new OverridableValue<decimal>(CalculateExcessWages);
public decimal ExcessWages
{
get { return _excessWages.Get(); }
set { _excessWages.Set(value); }
}
...
}
The advantage is that the whole logic is hidden at the class.

You could do this by defining a handy set/get helper method
private static T GetUtil<T>(ref Nullable<T> value, Func<T> calc) {
return value ?? calc();
}
private static void SetUtil<T>(ref Nullable<T> value, T newValue, Func<T> calc) {
if ( newValue != calc() ) {
value = newValue
} else {
value = null;
}
}
private Nullable<decimal> _excessWages;
public decimal ExcessWages
{
get { return GetUtil(ref _excessWages, CalculateExcessWages); }
set { SetUtil(ref _excessWages, value CalculateExcessWages); }
}

That looks reasonable to my eyes. The only change I might make is to cache CalculateExcessWages(), if it is expensive to do, and ok to cache:
private Nullable<decimal> _excessWages;
private Nullable<decimal> _excessWagesCalculated;
public virtual decimal ExcessWages
{
get
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
return _excessWages ?? _excessWagesCalculated;
}
set
{
if (_excessWagesCalculated == null)
_excessWagesCalculated = CalculateExcessWages();
if (value != _excessWagesCalculated)
_excessWages = value;
else
_excessWages = null;
}
}
But, this is more code than yours, and I think you are looking to simplify.

Related

Shorten syntax for nearly identical properties

I have to rework some code and stumbled upon a few classes which define a huge amount of very similar properties.
They look something like this:
public _ReturnType _PropertyName
{
get
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(_string, out value);
return value as _ReturnType;
}
set { Properties[_string] = value; }
}
The only difference between them is the _ReturnType, the _string that is used in the dictionary Properties and obviously the _PropertyName.
I was wondering if there is a way to shorten the syntax?
If you see duplicate code, you extract a method. It would look something like this:
private T GetValueOrDefault<T>(string key)
{
IMarkerInterface value = null;
if (Properties != null) Properties.TryGetValue(key, out value);
return value as T;
}
Then change your getter:
get
{
return GetValueOrDefault<_ReturnType>("key");
}
But if this code is spread out over multiple classes, you'd have to define a base class containing the Properties property and the above GetValueOrDefault() method, albeit protected instead of private.
Alternatively, you'd define it as an extension method on whatever the type of Properties is:
public static T GetValueOrDefault<T>(this IDictionary<string, IMarkerInterface> properties, string key)
{
IMarkerInterface value = null;
if (properties != null) properties.TryGetValue(key, out value);
return value as T;
}
And call it as such:
get
{
return Properties.GetValueOrDefault<_ReturnType>("key");
}
But, as #Daniel comments, this smells like an ideal scenario for code generation, because without that you'd still have a couple of lines of (copy-pasted, error-prone) code.
There probably is a source somewhere for what these properties should be named, and you can use something like T4 templates to generate this code file from it.
Well, you could do this:
private IMarkerInterface getIMF(string str)
{
IMarkerInterface value = null;
Properties?.TryGetValue(_string, out value);
return value;
}
public _ReturnType _PropertyName
{
get { return getIMF(_string) as _ReturnType; }
set { Properties[_string] = value; }
}
If Properties implements IReadOnlyDictionary<string, object> (like a Dictionary<string, object> for instance), one thing you could do is add an extension method:
public static TValue TryGetValue<TValue>(
this IReadOnlyDictionary<string, object> properties,
string key)
where TValue : class
{
if ((properties != null) &&
properties.TryGetValue(key, out object value))
{
return value as TValue;
}
return null;
}
and then
public IMarkerInterface MarkerInterface
{
get => Properties.TryGetValue<IMarkerInterface>("MarkerInterface");
set { Properties["MarkerInterface"] = value; }
}
Link to Fiddle

Workaround for C# properties with arguments

I know the fact that C# doesn't support properties with arguments except the default properties. But I think still it's nice to have such feature in some situations. As an example, an application might have settings which are specific to the language currently used. So such settings property may look like this.
settings.IsContentDownloaded["en-US"] = true;
Event thought this doesn't support by default, we can come up with a workaround to simulate this with other great feature available in the language. But the problem is what is the best workaround which provide a generalized approach to this problem.
I have my own workaround for this and I have shared it as an answer. But I'm looking for a better approach or any improvement to my approach.
create a dictionary where the keys are your strings such as "en-US" and the values are a bool:
Dictionary<string, bool> aaa = new Dictionary<string, bool>();
aaa.Add("en-US", true);
if(aaa["en-US"].Equals(true))
{
}
Its an interesting question, here is a method I came up with:
public class LocalizableSetting<T> : IEnumerable<KeyValuePair<string, T>>
{
private Dictionary<string, T> _values;
public T this[string cultureName]
{
get { return _values[cultureName]; }
set
{
_values[cultureName] = value;
}
}
public IEnumerator<KeyValuePair<string, T>> GetEnumerator()
{
return _values.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return _values.GetEnumerator();
}
public static implicit operator T(LocalizableSetting<T> value)
{
return value[CultureInfo.CurrentCulture.Name];
}
public static implicit operator LocalizableSetting<T>(T value)
{
var setting = new LocalizableSetting<T>();
setting[CultureInfo.CurrentCulture.Name] = value;
return setting;
}
}
Here LocalizableSetting stores localized values in an internal dictionary, which is really nothing special, however I added a feature that allows it to be used like normal properties as well, the implicit conversion operators.
This does take some tricks to use though, in order to properly use it in a class, you cannot use auto-properties, since you have to merge the two on a set, not overwrite it, so here is an example of how to use it in a class:
public class SomeLocalizableClass
{
//Explicitly declare the backing field for the property!
private LocalizableSetting<int> _intSetting = new LocalizableSetting<int>();
public LocalizableSetting<int> IntSetting
{
get { return _intSetting; }
set
{
//Merge, don't overwrite
foreach (var kvp in value)
_intSetting[kvp.Key] = kvp.Value;
}
}
}
Notice that in the set method, it iterates through the values and either overwrites the current one or adds a new one (with the help of the indexer).
So, this allows you to do something like this:
public class SomeConsumerClass
{
public void SomeMethod()
{
SomeLocalizableClass c = new SomeLocalizableClass();
c.IntSetting["fr-FR"] = 4; //Sets the french setting
c.IntSetting = 10; //Sets the current culture setting
int multipleSetting = c.IntSetting * c.IntSetting;
}
}
Where multipleSetting will be the multiple of the current culture values for that property due to the implicit conversion from LocalizableSetting<int> to int. The c.IntSetting = 10 causes an implicit conversion from the source type (int) to a LocalizableSetting<int> and then assigns it to the property, this is why a merge is needed instead of an overwrite.
There are a couple (big) holes that I left here, namely that the property should return some default value if the value for that culture is not found (currently it will throw an exception). But it shows one method of solving this issue.
I have used dictionary named _settingsRepositoty to store settings, but it might be anything which use to store setting based on the application type.
public class Settings
{
private Dictionary<string, object> _settingsRepository = new Dictionary<string, object>();
private LanguageSpecificPropertyFactory _factory;
public Settings()
{
_factory = new LanguageSpecificPropertyFactory(this);
}
public LanguageSpecificProperty<bool> IsContentDownloaded
{
get
{
return _factory.GetLanguageProperty("IsContentDownloaded", false);
}
}
private void Set<T>(string propertyName, string lang, T val)
{
string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
_settingsRepository[fullPropertyName] = val;
}
private T Get<T>(string propertyName, string lang, T defaultValue)
{
string fullPropertyName = string.Format("{0}_{1}", propertyName, lang);
if (!_settingsRepository.ContainsKey(fullPropertyName))
{
_settingsRepository[fullPropertyName] = defaultValue;
}
return (T)_settingsRepository[fullPropertyName];
}
public class LanguageSpecificProperty<T>
{
private string _properyName;
private T _defaultValue;
private Settings _settings;
internal LanguageSpecificProperty(Settings settings, string propertyName, T defaultValue)
{
_properyName = propertyName;
_defaultValue = defaultValue;
}
public T this[string lang]
{
get
{
return _settings.Get<T>(_properyName, lang, _defaultValue);
}
set
{
_settings.Set<T>(_properyName, lang, value);
}
}
}
public class LanguageSpecificPropertyFactory
{
private Dictionary<string, object> _properties = new Dictionary<string, object>();
private Settings _settings;
public LanguageSpecificPropertyFactory(Settings settings)
{
_settings = settings;
}
internal LanguageSpecificProperty<T> GetLanguageProperty<T>(string propertyName, T defaultValue)
{
if (!_properties.ContainsKey(propertyName))
{
_properties.Add(propertyName, new LanguageSpecificProperty<T>(_settings, propertyName, defaultValue));
}
return (LanguageSpecificProperty<T>)_properties[propertyName];
}
}
}

Maybe class and optional parameters [duplicate]

This question already has answers here:
Optional delegates in C# [duplicate]
(4 answers)
Closed 9 years ago.
I have an implementation of a Maybe / Option class in c#. Basic implementation is
public delegate Maybe<TOutput> Converter<in TInput, out TOutput>(TInput input);
public delegate TOutput ElseDelegate<out TOutput>();
public delegate Maybe<TOutput> ElseDelegate2<out TOutput>();
public interface Maybe<out TResult> : IEnumerable<TResult>
{
Maybe<B> Bind<B>(Converter<TResult, B> f);
TResult Value();
bool IsSome();
}
public static class Maybe
{
public static Maybe<T> None<T>()
{
return new None<T>();
}
}
public interface INone<out TResult> : Maybe<TResult>
{
}
public interface ISome<out TResult> : Maybe<TResult>
{
}
public struct None<TResult> : INone<TResult>
{
public IEnumerator<TResult> GetEnumerator()
{ yield break; }
IEnumerator IEnumerable.GetEnumerator()
{ yield break; }
public bool IsSome() { return false; }
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f)
{
return new None<TOutput>();
}
public TResult Value()
{
throw new IndexOutOfRangeException("None has no value");
}
}
public struct Some<TResult> : Maybe<TResult>
{
private TResult _Value;
public Some(TResult value)
{
_Value = value;
}
public IEnumerator<TResult> GetEnumerator()
{ yield return _Value; }
IEnumerator IEnumerable.GetEnumerator()
{ yield return _Value; }
public bool IsSome() { return true; }
public Maybe<TOutput> Bind<TOutput>(Converter<TResult, TOutput> f)
{
return f(_Value);
}
public TResult Value()
{
return this._Value;
}
}
#endregion
with a bunch of extension methods I have not included here. This all works
fine. However a standard pattern I would like to implement is below,
using Maybe to implement optional parameter defaults as in F#
void DoSomeCalc
( Maybe<double> x = Maybe.None<double>()
, Maybe<double> y = Maybe.None<double>()
)
{
this.X = x.Else( ()=> CalculateDefaultX() );
this.Y = y.Else( ()=> CalculateDefaultY() );
}
so I can do
DoSomeCalc(x:10)
or
DoSomeCalc(y:20)
where Else provides a value if None is available. However
this is all nice in theory but C# optional parameters
must be compile time constants which completely screws
this pattern.
Can anybody suggest a fix that will keep the intent of
the pattern without introducing nullables or nulls here?
Is there anyway I can create a compile time constant to
represent None here that will work with my above
implementation of Maybe?
No, there's nothing you can do here. Your parameter type is a reference type, which means the only constant values available are null and string literals. (Obviously string literals aren't useful in your case; I only mention them as the only kind of non-null reference type constant.)
One option would be to make Maybe<T> a struct instead of an interface, with the default value the "none" value. This would then be basically the same as Nullable<T> but without the constraint that T had to be a non-nullable value type. You could then use:
void DoSomeCalc(Maybe<double> x = default(Maybe<double>),
Maybe<double> y = default(Maybe<double>))
Sample code showing all of this:
using System;
struct Maybe<T>
{
private readonly bool hasValue;
public bool HasValue { get { return hasValue; } }
private readonly T value;
public T Value
{
get
{
if (!hasValue)
{
throw new InvalidOperationException();
}
return value;
}
}
public Maybe(T value)
{
this.hasValue = true;
this.value = value;
}
public static implicit operator Maybe<T>(T value)
{
return new Maybe<T>(value);
}
}
class Test
{
static void DoSomeCalc(Maybe<double> x = default(Maybe<double>),
Maybe<double> y = default(Maybe<double>))
{
Console.WriteLine(x.HasValue ? "x = " + x.Value : "No x");
Console.WriteLine(y.HasValue ? "y = " + y.Value : "No y");
}
static void Main()
{
Console.WriteLine("First call");
DoSomeCalc(x: 10);
Console.WriteLine("Second call");
DoSomeCalc(y: 20);
}
}
Obviously you'd want to add more functionality to Maybe<T>, such as overriding ToString and Equals, but you get the general idea. You can still have a non-generic Maybe class with factory methods too, of course.
You can use null internally to mean Maybe.None<double>(). E.g.:
double DoSomeCalc
( Maybe<double> x = null
, Maybe<double> y = null
)
{
x = x ?? Maybe.None<double>();
y = y ?? Maybe.None<double>();
this.X = x.Else( ()=> CalculateDefaultX() );
this.Y = y.Else( ()=> CalculateDefaultY() );
}
It is not ideal as you have to document somewhere in comments that passing null means "use a particular default".

implicit or explicit conversion from T to T[]

Is there a way to implement a generic implicit or explicit converter for anything to an array of anything, something like this:
public static implicit operator T[](T objToConvert)
{
return new T[] { objToConvert };
}
No. The closest I can think of is an extension method:
public static T[] AsArray<T>(this T instance)
{
return new T[]{instance};
}
Use as:
var myArray = myInstnace.AsArray();
Note that you can omit the type name from the array constructor, which means the syntax is fairly clean, even with a long type name:
ReallyLongAndAwkwardTypeName value;
MethodThatTakesArray(new[] {value});
Operator overloading methods have to live inside the class they are overriding operators for (one side or the other). Since "T" is not defined, I don't see how this can be accomplished.
You can do it using normal method:
public static T[] ToArray<T>(T objToConvert) {
return new T[] { objToConvert };
}
I don't think you can define generics operator. Note, anyway, that the compiler is sufficient cleaver to guess the type of the generic param, so you can use:
var aString="";
var aStringArray=ToArray(aString);
aStringArray is defined as a string array even if you don't specify the generic param.
I was trying to think of situations where you might really use an implicit conversion to array. I started to wonder if many of the situations where you would want to do this could be alleviated by use of the params keyword.
The main situation that I could think of was that you had a single item of something and wanted to pass it to a function that takes an array as a parameter:
static void Main(string[] args)
{
string x = "I'm just a poor variable. Nobody loves me.";
Stickler.IOnlyTakeArrays_Rawr111(x); // won't go in! square peg, round hole, etc.
// *sigh* fine.
Stickler.IOnlyTakeArrays_Rawr111(new[] { x });
}
class Stickler
{
public static void IOnlyTakeArrays_Rawr111(string[] yum)
{
// ...
}
}
Hopefully in this situation the author of the method that you want to call has choosen to use the params keyword to allow you to pass your variable without wrapping it in an array:
class DataConcierge
{
public static T Create<T>(int id)
{
// ...
}
public static void Save<T>(params T[] items)
{
// ...
}
}
static void Main(string[] args)
{
var customer = DataConcierge.Create<Customer>(123);
// ...
DataConcierge.Save(customer); // this works!
//----------------------------------------------------
// or
//----------------------------------------------------
var customers = new Customer[]
{
DataConcierge.Create<Customer>(123),
DataConcierge.Create<Customer>(234),
DataConcierge.Create<Customer>(345),
};
// ...
DataConcierge.Save(customers); // this works too!
}
Of course, this doesn't really help you in situations where you need convert a variable to a single item array but not as a parameter to a method or in situations where the author of the method didn't use the params keyword.
But what kind of situation would the former be? Assigning an array to a property? Psh. How often does that happen?
And the latter? If the author didn't use the params keyword when they could have, then send them an email complaining about it. If the author is yourself, feel free to be extra belligerent in the email.
Hopefully you can tell that I'm being facetious. Seriously, though, are there any other common usage situations that you can think of where the params keyword would not be applicable?
** Disclaimer: I don't advocate excessive use of the params keyword. Use it if you think you should, but don't take my post to mean that you should always use the params keyword whenever you can.
In the past I've used the concept of a "Conductor" (my own name for it), which is just a class/struct that provides access to an underlying value.
The concept is useful for abstracting the access to a particular value retrieved from somewhere. For example, if you wanted to abstract access to a particular value in a dictionary, you could create a Conductor object that held a reference to the dictionary and the appropriate key for that value. You can also use this concept to easily implement rollback for serializable classes or for value types, though for that you'd need to add Rollback and Commit methods to the Conductor class/struct.
Below is an example of how you can use implicit conversions from T to Conductor and from Conductor to T[] in order to (sort of) achieve what you want.
static void Main(string[] args)
{
// implicit conversion here from Customer to Conductor<Customer>
Conductor<Customer> conductor = DataConcierge.Create<Customer>(123);
if (conductor.HasValue)
{
Console.WriteLine("I got a customer with Id {0}!", conductor.Value.Id);
// implicit conversion here from Conductor<Customer> to Customer[]
DataConcierge.Save<Customer>(conductor);
}
}
public struct Conductor<T> : IConductor<T>, IEquatable<T>, IEquatable<Conductor<T>>, IEquatable<IConductor<T>>
{
private T _Value;
public Conductor(T value)
{
this._Value = value;
}
public T Value
{
get { return this._Value; }
set { this._Value = value; }
}
public bool HasValue
{
get { return this._Value != null; }
}
public T GetValueOrDefault()
{
if (this.HasValue)
return this.Value;
else
return default(T);
}
public T GetValueOrDefault(T #default)
{
if (this.HasValue)
return this.Value;
else
return #default;
}
public bool TryGetValue(out T value)
{
if (this.HasValue)
{
value = this.Value;
return true;
}
else
{
value = default(T);
return false;
}
}
public T[] AsArray()
{
return new T[] { this._Value };
}
public static implicit operator Conductor<T>(T value)
{
return new Conductor<T>(value);
}
public static implicit operator T(Conductor<T> conductor)
{
return conductor.Value;
}
public static implicit operator T[](Conductor<T> conductor)
{
return conductor.AsArray();
}
public bool Equals(T other)
{
var otherEquatable = other as IEquatable<T>;
if (otherEquatable != null)
return otherEquatable.Equals(this.Value);
else
return object.Equals(this.Value, other);
}
public bool Equals(Conductor<T> other)
{
if (other.HasValue)
return this.Equals(other.Value);
else
return !this.HasValue;
}
public bool Equals(IConductor<T> other)
{
if (other != null && other.HasValue)
return this.Equals(other.Value);
else
return !this.HasValue;
}
public override bool Equals(object obj)
{
if (obj == null)
return !this.HasValue;
var conductor = obj as IConductor<T>;
if (conductor != null)
{
if (conductor.HasValue)
return this.Equals(conductor.Value);
else
return !this.HasValue;
}
return object.Equals(this.Value, obj);
}
public override int GetHashCode()
{
if (this.HasValue)
return this.Value.GetHashCode();
else
return 0;
}
public override string ToString()
{
if (this.HasValue)
return this.Value.ToString();
else
return null;
}
}

Implement a function as []

I have an array which really is a function, however i would like to use it as an array. I know i can write these
int var { get{return v2;} }
public int this[int v] { get { return realArray[v]; }
but how do i implement a function that like an array? i would like to do something like
public int pal[int i] { get { return i*2; } }
But that get a compile error
error CS0650: Bad array declarator: To declare a managed array the rank specifier precedes the variable's identifier. To declare a fixed size buffer field, use the fixed keyword before the field type.
error CS0270: Array size cannot be specified in a variable declaration (try initializing with a 'new' expression)
In C#, the only possible way to declare a parameterized property is an indexer. However, you could simulate something like that by creating a class that provides an indexer and adding a property of that type to your class:
class ParameterizedProperty<TProperty, TIndex> {
private Func<TIndex, TProperty> getter;
private Action<TIndex, TProperty> setter;
public ParameterizedProperty(Func<TIndex, TProperty> getter,
Action<TIndex, TProperty> setter) {
this.getter = getter;
this.setter = setter;
}
public TProperty this[TIndex index] {
get { return getter(index); }
set { setter(index, value); }
}
}
class MyType {
public MyType() {
Prop = new ParameterizedProperty<string, int>(getProp, setProp);
}
public ParameterizedProperty<string, int> Prop { get; private set; }
private string getProp(int index) {
// return the stuff
}
private void setProp(int index, string value) {
// set the stuff
}
}
MyType test = new MyType();
test.Prop[0] = "Hello";
string x = test.Prop[0];
You can extend the idea to read only and write only properties by removing getter or setter from the class as appropriate.
As you noticed, you cannot name an indexer like that, so either:
public int this[int i] { get { return i * 2; } }
Or alternatively if you are really set on naming it pal:
public class Wrapper
{
public int this[int i] { get { return i * 2; } }
}
...
public Wrapper pal { get { return _someWrapperInstance; } }
Which can then be accessed pal[ix], pal[3], etc.
Either you return an array object:
public int[] pal { get { return realArray; } }
or you return an object that has an indexer:
public class ActingAsArray {
private int[] _arr;
public ActingAsArray(int[] arr) { _arr = arr; }
public int this[int v] { get { return _arr[v]; } }
}
public ActingAsArray pal { get { return new ActingAsArray(realArray); } }
You cannot overload (overloadable operators) the bracket operator in C#. The best you can do is implement an indexer, as you have shown. As per the documentation, you must use the this keyword to implement an indexer. Indexers work much like properties, they have a getter and a setter and you can perform just about any function in the getter or setter.
If you don't mind using a bit of VB.Net, it supports parameterized properties (still beats me why it's not possible in C#, as .Net is obviously capable of doing it)
This way you could create your class in VB.Net and just reference the VB.Net DLL in your project.
This could of course get somewhat annoying if your class changes often :-/

Categories

Resources