Asynchronously invoking a method with an output parameter - c#

Is it possible to use a TPL Task<TResult> to asynchronously invoke a thread-safe method with the following signature and retrieve the boolean return value and the output parameter?
public bool TryGet(T1 criteria,
out T2 output)
Obviously I can't use a lambda expression because of the output parameter. Additionally, I cannot solve the problem by defining a custom delegate such as below and passing that to the Task<TResult> constructor as I need to pass the criteria as a strongly typed parameter which the constructor does not support.
public delegate TResult Func<T1, T2, TResult>(T1 arg1,
out T2 arg2);
Is the best option to write a wrapper such as below and invoke that asynchronously instead?
public Tuple<bool, T2> TryGetWrapper(T1 criteria)
{
T2 output;
bool result = obj.TryGet(criteria,
out output);
return new Tuple<bool, T2>(result,
output);
}
Just seems a bit inelegant and has a bit of a whiff about it.

This is something I've also wrestled with.
I came up with a similar solution, except rather than use a Tuple I wrote a simple wrapper class, just to make things a bit more readable.
I'd also be interested to see any better solution - but what you propose seems as good as anything I came up with.
Here's what my wrapper class and its usage looks like. This is not an answer to your question; just a suggestion to (perhaps) make your solution a bit more readable.
(Although I concede that the Task<TryResult<DateTime>> declaration itself might not be considered all that readable!)
using System;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
internal class Program
{
static void Main()
{
string dateString = "Invalid Date";
var tryParseDateTask = new Task<TryResult<DateTime>>(() =>
{
DateTime result;
if (DateTime.TryParse(dateString, out result))
return TryResult<DateTime>.Success(result);
else
return TryResult<DateTime>.Failure();
});
tryParseDateTask.Start();
if (tryParseDateTask.Result.IsSuccessful)
Console.WriteLine(dateString + " was parsed OK.");
else
Console.WriteLine(dateString + " was parsed as " + tryParseDateTask.Result.Value);
}
}
public class TryResult<T>
{
public static TryResult<T> Success(T value)
{
return new TryResult<T>(value, true);
}
public static TryResult<T> Failure()
{
return new TryResult<T>(default(T), false);
}
TryResult(T value, bool isSuccessful)
{
this.value = value;
this.isSuccessful = isSuccessful;
}
public T Value
{
get
{
return value;
}
}
public bool IsSuccessful
{
get
{
return isSuccessful;
}
}
readonly T value;
readonly bool isSuccessful;
}
}

I think your approach is pretty much the best you can do. If you are doing this often, you could use a helper method that convert a delegate with out parameter to a Tuple-returning delegate (or something like TryResult-returning, as in Matthew Watson's answer):
public delegate TResult OutFunc<TIn, TOut, TResult>(TIn input, out TOut output);
public static Func<TIn, Tuple<TResult, TOut>> OutToTuple<TIn, TOut, TResult>(
OutFunc<TIn, TOut, TResult> outFunc)
{
return input =>
{
TOut output;
TResult result = outFunc(input, out output);
return Tuple.Create(result, output);
};
}

Related

Generic method to map objects of different types

I would like to write Generic Method that would map List to new list, similar to JS's map method. I would then use this method like this:
var words= new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
List<object> wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
I know there's Select method which does the same thing but I need to write my own method. Right now I have this:
public static IEnumerable<object> SelectMy<T>(this IEnumerable<T> seznam, Predicate<T> predicate)
{
List<object> ret = new List<object>();
foreach (var el in seznam)
ret.Add(predicate(el));
return ret;
}
I also know I could use yield return but again I mustn't. I think the problem is with undeclared types and compiler can't figure out how it should map objects but I don't know how to fix that. All examples and tutorials I found map object of same types.
Linq's Select is the equivalent of the map() function in other functional languages. The mapping function would typically not be called Predicate, IMO - predicate would be a filter which could reduce the collection.
You can certainly wrap an extension method which would apply a projection to map input to output (either of which could be be anonymous types):
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
foreach (var item in seznam)
yield return mapper(item);
}
Which is equivalent to
public static IEnumerable<TO> Map<TI, TO>(this IEnumerable<TI> seznam,
Func<TI, TO> mapper)
{
return seznam.Select(mapper);
}
And if you don't want a strong return type, you can leave the output type as object
public static IEnumerable<object> Map<TI>(this IEnumerable<TI> seznam, Func<TI, object> mapper)
{
// Same implementation as above
And called like so:
var words = new List<string>() { "Kočnica", "druga beseda", "tretja", "izbirni", "vodno bitje" };
var wordsMapped = words.Map(el => new { cela = el, končnica = el.Končnica(5) });
Edit
If you enjoy the runtime thrills of dynamic languages, you could also use dynamic in place of object.
But using dynamic like this so this precludes the using the sugar of extension methods like Končnica - Končnica would either need to be a method on all of the types utilized, or be invoked explicitly, e.g.
static class MyExtensions
{
public static int Končnica(this int i, int someInt)
{
return i;
}
public static Foo Končnica(this Foo f, int someInt)
{
return f;
}
public static string Končnica(this string s, int someInt)
{
return s;
}
}
And then, provided all items in your input implemented Končnica you could invoke:
var things = new List<object>
{
"Kočnica", "druga beseda",
53,
new Foo()
};
var mappedThings = things.Map(el => new
{
cela = el,
končnica = MyExtensions.Končnica(el, 5)
// Or el.Končnica(5) IFF it is a method on all types, else run time errors ...
})
.ToList();
You can fix your code to work correctly like this:
public static IEnumerable<TResult> SelectMy<T, TResult>(this IEnumerable<T> seznam,
Func<T, TResult> mapping)
{
var ret = new List<TResult>();
foreach (var el in seznam)
{
ret.Add(mapping(el));
}
return ret;
}
Note that this is inefficient and problematic compared to typical Linq extensions, because it enumerates the entire input at once. If the input is an infinite series, you are in for a bad time.
It is possible to remedy this problem without the use of yield, but it would be somewhat lengthy. I think it would be ideal if you could tell us all why you are trying to do this task with two hands tied behind your back.
As a bonus, here is how you could implement this with the lazy evaluation benefits of yield without actually using yield. This should make it abundantly clear just how valuable yield is:
internal class SelectEnumerable<TIn, TResult> : IEnumerable<TResult>
{
private IEnumerable<TIn> BaseCollection { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerable(IEnumerable<TIn> baseCollection,
Func<TIn, TResult> mapping)
{
BaseCollection = baseCollection;
Mapping = mapping;
}
public IEnumerator<TResult> GetEnumerator()
{
return new SelectEnumerator<TIn, TResult>(BaseCollection.GetEnumerator(),
Mapping);
}
IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); }
}
internal class SelectEnumerator<TIn, TResult> : IEnumerator<TResult>
{
private IEnumerator<TIn> Enumerator { get; set; }
private Func<TIn, TResult> Mapping { get; set; }
internal SelectEnumerator(IEnumerator<TIn> enumerator,
Func<TIn, TResult> mapping)
{
Enumerator = enumerator;
Mapping = mapping;
}
public void Dispose() { Enumerator.Dispose(); }
public bool MoveNext() { return Enumerator.MoveNext(); }
public void Reset() { Enumerator.Reset(); }
public TResult Current { get { return Mapping(Enumerator.Current); } }
object IEnumerator.Current { get { return Current; } }
}
internal static class MyExtensions
{
internal static IEnumerable<TResult> MySelect<TIn, TResult>(
this IEnumerable<TIn> enumerable,
Func<TIn, TResult> mapping)
{
return new SelectEnumerable<TIn, TResult>(enumerable, mapping);
}
}
The problem with your code is that Predicate<T> is a delegate that returns a boolean, which you're then trying to add to a List<object>.
Using a Func<T,object> is probably what you're looking for.
That being said, that code smells bad:
Converting to object is less than useful
Passing a delegate that maps T to an anonymous type won't help - you'll still get an object back which has no useful properties.
You probably want to add a TResult generic type parameter to your method, and take a Func<T, TResult> as an argument.

Passing a method with parameter Func<T> and getting TResult

So basically T has a return type, I want to get back the generic return type. Example:
private TResult EndInvoke<T, TResult>(Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
TResult result = default(TResult);
try
{
result = asyncCaller.EndInvoke(asyncResult);
}
catch (Exception exception)
{
// get exception details.
}
return result;
}
How do I pass just the T calling the method and get the TResult?
Mind you, I only have the T.
EDIT: I meant how do I call this method?
EDIT: I want a generic EndInvoke, because I am a huge try catch on different EndInvokes, then I want the result from the EndInvoke.
I suggest converting your generic EndInvoke<,> method to an extension method first.
public static class FuncExtensions
{
public static TResult EndInvoke<T, TResult>(this Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
// ...
}
}
This will simplify the method call. As an example, I'll call a method that calculates the square of an integer.
private int Square(int x)
{
return x * x;
}
In your client code, you'd call it like this:
Func<int, int> caller = new Func<int, int>(Square);
int x = 5;
int y = default(int);
caller.BeginInvoke(x,
asyncResult =>
{
y = caller.EndInvoke(asyncResult);
},
null);
Console.WriteLine("The square of {0} is {1}", x, y);
EDIT
This example has not been tested in any way, and contains an obvious race condition.
Not sure that I understand correctly, but I think that if you want the Func return value, you should drop the IAsyncResult.
Example:
private TResult GetResult<T, TResult>(Func<T, TResult> asyncCaller, IAsyncResult asyncResult)
{
TResult result = default(TResult);
result = asyncCaller(argument...);
return result;
}

Generically encapsulate action/function with class?

I would like to provide encapsulation of actions/methods generically. I think this should be possible in C# but I'm not able to produce it so it compiles...
The following briefly demonstrates what I want. Is this possible somehow, perhaps by generalizing the class?
Required is:
I want to execute the function/action (see method type) and 'do something' when an error occurs
I want to return the value of the function if the method is a function (otherwise return void if possible)
I want to 'do something' if the return type of the function is a boolean and the value is false.
public class Encapsulator {
private Action _action;
private Func<T> _function;
private MethodType _type; //Action || Function
public Encapsulator(Action action) {
this._action = action;
this._type = MethodType.Action;
}
public Encapsulator(Func<T> func) { //This is not accepted
this._function = func;
this._type = MethodType.Function;
}
public void Execute() {
try {
this._action();
}
catch(Exception ex) {
//do something
throw;
}
}
public T Execute<T>() {
try {
var r = this._function();
if(typeof(r) == bool) {
if(!r)
//do something
}
return r;
} catch(Exception ex) {
//do something
throw;
}
}
}
Your second constructor won't compile because their are no generics applied to the type at the higher level:
public Encapsulator<T>
{
public Encapsulator(Func<T> func)
{
this._function = func;
this._type = MethodType.Function;
}
}
Instead of just introducing new things within the parameters of a method, essentially, we need to specify that those things are 'available' for utilisation in the definitions. So, for instance, if you were trying to add a specific generic method, you could apply it as you have done, but would instead need to do (something which you demonstrate with the Execute method):
public void MyGenericMethod<T>(Func<T> func)
{
}
Noting the first T, we're specifying the existence of T, as such.
There are possibly more issues at hand with your code here, but I believe, on first glance, this to be the crux of the problems you're having.
As for returning variable types, the best you might hope for is returning a plain old object. Or, making use of the dynamic type, however, I wouldn't have thought this would be the way to go and wouldn't recommend it; you can't flip return type from an actual type to a void, though.
New Approach: The action Encapsulator will now return a dummy result (always true).
public class Encapsulator
{
public static Encapsulator<bool> CreateEncapsulator(Action action)
{
return new Encapsulator<bool>(() =>
{
action();
return true;
});
}
public static Encapsulator<T> CreateEncapsulator<T>(Func<T> func)
{
return new Encapsulator<T>(func);
}
}
public class Encapsulator<T>
{
private Func<T> _function;
internal Encapsulator(Func<T> func)
{
this._function = func;
}
public T Execute()
{
try
{
object res = this._function();
Nullable<bool> bres = res as Nullable<bool>;
if (bres.HasValue)
{
if (!bres.Value)
Console.WriteLine("NOT TRUE!");
//do something
}
return (T)res;
}
catch (Exception ex)
{
//do something
throw;
}
}
}
Calling the code:
var withDummyReturn = Encapsulator.CreateEncapsulator(() => Console.WriteLine("Great"));
withDummyReturn.Execute();
var withReturn = Encapsulator.CreateEncapsulator<bool>(() => true);
bool res = withReturn.Execute();

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;
}
}

Passing properties by reference in C#

I'm trying to do do the following:
GetString(
inputString,
ref Client.WorkPhone)
private void GetString(string inValue, ref string outValue)
{
if (!string.IsNullOrEmpty(inValue))
{
outValue = inValue;
}
}
This is giving me a compile error. I think its pretty clear what I'm trying to achieve. Basically I want GetString to copy the contents of an input string to the WorkPhone property of Client.
Is it possible to pass a property by reference?
Properties cannot be passed by reference. Here are a few ways you can work around this limitation.
1. Return Value
string GetString(string input, string output)
{
if (!string.IsNullOrEmpty(input))
{
return input;
}
return output;
}
void Main()
{
var person = new Person();
person.Name = GetString("test", person.Name);
Debug.Assert(person.Name == "test");
}
2. Delegate
void GetString(string input, Action<string> setOutput)
{
if (!string.IsNullOrEmpty(input))
{
setOutput(input);
}
}
void Main()
{
var person = new Person();
GetString("test", value => person.Name = value);
Debug.Assert(person.Name == "test");
}
3. LINQ Expression
void GetString<T>(string input, T target, Expression<Func<T, string>> outExpr)
{
if (!string.IsNullOrEmpty(input))
{
var expr = (MemberExpression) outExpr.Body;
var prop = (PropertyInfo) expr.Member;
prop.SetValue(target, input, null);
}
}
void Main()
{
var person = new Person();
GetString("test", person, x => x.Name);
Debug.Assert(person.Name == "test");
}
4. Reflection
void GetString(string input, object target, string propertyName)
{
if (!string.IsNullOrEmpty(input))
{
var prop = target.GetType().GetProperty(propertyName);
prop.SetValue(target, input);
}
}
void Main()
{
var person = new Person();
GetString("test", person, nameof(Person.Name));
Debug.Assert(person.Name == "test");
}
I wrote a wrapper using the ExpressionTree variant and c#7 (if somebody is interested):
public class Accessor<T>
{
private Action<T> Setter;
private Func<T> Getter;
public Accessor(Expression<Func<T>> expr)
{
var memberExpression = (MemberExpression)expr.Body;
var instanceExpression = memberExpression.Expression;
var parameter = Expression.Parameter(typeof(T));
if (memberExpression.Member is PropertyInfo propertyInfo)
{
Setter = Expression.Lambda<Action<T>>(Expression.Call(instanceExpression, propertyInfo.GetSetMethod(), parameter), parameter).Compile();
Getter = Expression.Lambda<Func<T>>(Expression.Call(instanceExpression, propertyInfo.GetGetMethod())).Compile();
}
else if (memberExpression.Member is FieldInfo fieldInfo)
{
Setter = Expression.Lambda<Action<T>>(Expression.Assign(memberExpression, parameter), parameter).Compile();
Getter = Expression.Lambda<Func<T>>(Expression.Field(instanceExpression,fieldInfo)).Compile();
}
}
public void Set(T value) => Setter(value);
public T Get() => Getter();
}
And use it like:
var accessor = new Accessor<string>(() => myClient.WorkPhone);
accessor.Set("12345");
Assert.Equal(accessor.Get(), "12345");
without duplicating the property
void Main()
{
var client = new Client();
NullSafeSet("test", s => client.Name = s);
Debug.Assert(person.Name == "test");
NullSafeSet("", s => client.Name = s);
Debug.Assert(person.Name == "test");
NullSafeSet(null, s => client.Name = s);
Debug.Assert(person.Name == "test");
}
void NullSafeSet(string value, Action<string> setter)
{
if (!string.IsNullOrEmpty(value))
{
setter(value);
}
}
If you want to get and set the property both, you can use this in C#7:
GetString(
inputString,
(() => client.WorkPhone, x => client.WorkPhone = x))
void GetString(string inValue, (Func<string> get, Action<string> set) outValue)
{
if (!string.IsNullOrEmpty(outValue.get()))
{
outValue.set(inValue);
}
}
This is covered in section 7.4.1 of the C# language spec. Only a variable-reference can be passed as a ref or out parameter in an argument list. A property does not qualify as a variable reference and hence cannot be used.
Just a little expansion to Nathan's Linq Expression solution. Use multi generic param so that the property doesn't limited to string.
void GetString<TClass, TProperty>(string input, TClass outObj, Expression<Func<TClass, TProperty>> outExpr)
{
if (!string.IsNullOrEmpty(input))
{
var expr = (MemberExpression) outExpr.Body;
var prop = (PropertyInfo) expr.Member;
if (!prop.GetValue(outObj).Equals(input))
{
prop.SetValue(outObj, input, null);
}
}
}
Another trick not yet mentioned is to have the class which implements a property (e.g. Foo of type Bar) also define a delegate delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2); and implement a method ActOnFoo<TX1>(ref Bar it, ActByRef<Bar,TX1> proc, ref TX1 extraParam1) (and possibly versions for two and three "extra parameters" as well) which will pass its internal representation of Foo to the supplied procedure as a ref parameter. This has a couple of big advantages over other methods of working with the property:
The property is updated "in place"; if the property is of a type that's compatible with `Interlocked` methods, or if it is a struct with exposed fields of such types, the `Interlocked` methods may be used to perform atomic updates to the property.
If the property is an exposed-field structure, the fields of the structure may be modified without having to make any redundant copies of it.
If the `ActByRef` method passes one or more `ref` parameters through from its caller to the supplied delegate, it may be possible to use a singleton or static delegate, thus avoiding the need to create closures or delegates at run-time.
The property knows when it is being "worked with". While it is always necessary to use caution executing external code while holding a lock, if one can trust callers not to do too do anything in their callback that might require another lock, it may be practical to have the method guard the property access with a lock, such that updates which aren't compatible with `CompareExchange` could still be performed quasi-atomically.
Passing things be ref is an excellent pattern; too bad it's not used more.
This is not possible. You could say
Client.WorkPhone = GetString(inputString, Client.WorkPhone);
where WorkPhone is a writeable string property and the definition of GetString is changed to
private string GetString(string input, string current) {
if (!string.IsNullOrEmpty(input)) {
return input;
}
return current;
}
This will have the same semantics that you seem to be trying for.
This isn't possible because a property is really a pair of methods in disguise. Each property makes available getters and setters that are accessible via field-like syntax. When you attempt to call GetString as you've proposed, what you're passing in is a value and not a variable. The value that you are passing in is that returned from the getter get_WorkPhone.
Inspired by Sven's expression tree solution, below is a smplified version that doesn't rely on reflection. Also, it removes the unnecessary custom getter and field expressions.
using System;
using System.Linq.Expressions;
namespace Utils;
public class Accessor<T>
{
public Accessor(Expression<Func<T>> expression)
{
if (expression.Body is not MemberExpression memberExpression)
throw new ArgumentException("expression must return a field or property");
var parameterExpression = Expression.Parameter(typeof(T));
_setter = Expression.Lambda<Action<T>>(Expression.Assign(memberExpression, parameterExpression), parameterExpression).Compile();
_getter = expression.Compile();
}
public void Set(T value) => _setter(value);
public T Get() => _getter();
private readonly Action<T> _setter;
private readonly Func<T> _getter;
}
Properties cannot be passed by reference ? Make it a field then, and use the property to reference it publicly:
public class MyClass
{
public class MyStuff
{
string foo { get; set; }
}
private ObservableCollection<MyStuff> _collection;
public ObservableCollection<MyStuff> Items { get { return _collection; } }
public MyClass()
{
_collection = new ObservableCollection<MyStuff>();
this.LoadMyCollectionByRef<MyStuff>(ref _collection);
}
public void LoadMyCollectionByRef<T>(ref ObservableCollection<T> objects_collection)
{
// Load refered collection
}
}
What you could try to do is create an object to hold the property value. That way you could pass the object and still have access to the property inside.
To vote on this issue, here is one active suggestion of how this could be added to the language. I'm not saying this is the best way to do this (at all), feel free to put out your own suggestion. But allowing properties to be passed by ref like Visual Basic already can do would hugely help simplify some code, and quite often!
https://github.com/dotnet/csharplang/issues/1235
You can't ref a property, but if your functions need both get and set access you can pass around an instance of a class with a property defined:
public class Property<T>
{
public delegate T Get();
public delegate void Set(T value);
private Get get;
private Set set;
public T Value {
get {
return get();
}
set {
set(value);
}
}
public Property(Get get, Set set) {
this.get = get;
this.set = set;
}
}
Example:
class Client
{
private string workPhone; // this could still be a public property if desired
public readonly Property<string> WorkPhone; // this could be created outside Client if using a regular public property
public int AreaCode { get; set; }
public Client() {
WorkPhone = new Property<string>(
delegate () { return workPhone; },
delegate (string value) { workPhone = value; });
}
}
class Usage
{
public void PrependAreaCode(Property<string> phone, int areaCode) {
phone.Value = areaCode.ToString() + "-" + phone.Value;
}
public void PrepareClientInfo(Client client) {
PrependAreaCode(client.WorkPhone, client.AreaCode);
}
}
The accepted answer is good if that function is in your code and you can modify it. But sometimes you have to use an object and a function from some external library and you can't change the property and function definition. Then you can just use a temporary variable.
var phone = Client.WorkPhone;
GetString(input, ref phone);
Client.WorkPhone = phone;
It seems that you are needing to impose a business rule constraint on that field, while at the same time wanting to keep your code as DRY as possible.
It is achievable and also preserves your domain semantics by implementing a full property on that field and using your re-usable method:
public class Client
{
private string workPhone;
public string WorkPhone
{
get => workPhone;
set => SafeSetString(ref workPhone, value);
}
private void SafeSetString(ref string target, string source)
{
if (!string.IsNullOrEmpty(source))
{
target = source;
}
}
}
The SafeSetString method can be placed in a Utilities class or wherever it makes sense.
Yes, you can't pass a property but you can convert your property to a property with backing field and do something like this.
public class SomeClass
{
private List<int> _myList;
public List<int> MyList
{
get => return _myList;
set => _myList = value;
}
public ref List<int> GetMyListByRef()
{
return ref _myList;
}
}
but there are better solutions like action delegate etc.

Categories

Resources