F# has a convenient feature "with", example:
type Product = { Name:string; Price:int };;
let p = { Name="Test"; Price=42; };;
let p2 = { p with Name="Test2" };;
F# created keyword "with" as the record types are by default immutable.
Now, is it possible to define a similar extension in C#?
seems it's a bit tricky, as in C# i'm not sure how to convert a string
Name="Test2"
to a delegate or expression?
public static T With<T, U>(this T obj, Expression<Func<T, U>> property, U value)
where T : ICloneable {
if (obj == null)
throw new ArgumentNullException("obj");
if (property == null)
throw new ArgumentNullException("property");
var memExpr = property.Body as MemberExpression;
if (memExpr == null || !(memExpr.Member is PropertyInfo))
throw new ArgumentException("Must refer to a property", "property");
var copy = (T)obj.Clone();
var propInfo = (PropertyInfo)memExpr.Member;
propInfo.SetValue(copy, value, null);
return copy;
}
public class Foo : ICloneable {
public int Id { get; set; }
public string Bar { get; set; }
object ICloneable.Clone() {
return new Foo { Id = this.Id, Bar = this.Bar };
}
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = foo.With(x => x.Bar, "boo-ya");
Console.WriteLine(newFoo.Bar); //boo-ya
}
Or, using a copy constructor:
public class Foo {
public Foo(Foo other) {
this.Id = other.Id;
this.Bar = other.Bar;
}
public Foo() { }
public int Id { get; set; }
public string Bar { get; set; }
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = new Foo(foo) { Bar = "boo-ya" };
Console.WriteLine(newFoo.Bar);
}
And a slight variation on George's excellent suggestion, that allows for multiple assignments:
public static T With<T>(this T obj, params Action<T>[] assignments)
where T : ICloneable {
if (obj == null)
throw new ArgumentNullException("obj");
if (assignments == null)
throw new ArgumentNullException("assignments");
var copy = (T)obj.Clone();
foreach (var a in assignments) {
a(copy);
}
return copy;
}
public static void Test() {
var foo = new Foo { Id = 1, Bar = "blah" };
var newFoo = foo.With(x => x.Id = 2, x => x.Bar = "boo-ya");
Console.WriteLine(newFoo.Bar);
}
I would probably use the second one since (1) any general purpose solution is going to be unnecessarily slow and convoluted; (2) it has the closest syntax to what you want (and the syntax does what you expect); (3) F# copy-and-update expressions are implemented similarly.
Maybe something like this:
void Main()
{
var NewProduct = ExistingProduct.With(P => P.Name = "Test2");
}
// Define other methods and classes here
public static class Extensions
{
public T With<T>(this T Instance, Action<T> Act) where T : ICloneable
{
var Result = Instance.Clone();
Act(Result);
return Result;
}
}
As an alternative to lambda function, you can use parameters with default values. The only minor issue is that you have to pick some default value that means do not change this parameter (for reference types), but null should be a safe choice:
class Product {
public string Name { get; private set; }
public int Price { get; private set; }
public Product(string name, int price) {
Name = name; Price = price;
}
// Creates a new product using the current values and changing
// the values of the specified arguments to a new value
public Product With(string name = null, int? price = null) {
return new Product(name ?? Name, price ?? Price);
}
}
// Then you can write:
var prod2 = prod1.With(name = "New product");
You have to define the method yourself, but that's always the case (unless you're going to use reflection, which less efficient). I think the syntax is reasonably nice too. If you want to make it as nice as in F#, then you'll have to use F# :-)
There is no native ability to do this in C# short of an extension method, but at what cost? a and b are reference types and any suggestion that b is based ("with") on a causes immediate confusion as to how many objects we are working with. Is there only one? Is b a copy of a ? Does b point to a ?
C# is not F#.
Please see a previous SO question of mine as answered by Eric Lippert:
"Amongst my rules of thumb for writing clear code is: put all side effects in statements; non-statement expressions should have no side effects."
More fluent C# / .NET
Related
C# has the usefull Null Conditional Operator. Well explained in this answer too.
I was wondering if it is possible to do a similar check like this when my object is a dynamic/expando object. Let me show you some code:
Given this class hierarchy
public class ClsLevel1
{
public ClsLevel2 ClsLevel2 { get; set; }
public ClsLevel1()
{
this.ClsLevel2 = new ClsLevel2(); // You can comment this line to test
}
}
public class ClsLevel2
{
public ClsLevel3 ClsLevel3 { get; set; }
public ClsLevel2()
{
this.ClsLevel3 = new ClsLevel3();
}
}
public class ClsLevel3
{
// No child
public ClsLevel3()
{
}
}
If i perform this kind of chained null check, it works
ClsLevel1 levelRoot = new ClsLevel1();
if (levelRoot?.ClsLevel2?.ClsLevel3 != null)
{
// will enter here if you DO NOT comment the content of the ClsLevel1 constructor
}
else
{
// will enter here if you COMMENT the content of the ClsLevel1
}
Now, i will try to reproduce this behaviour with dynamics (ExpandoObjects)
dynamic dinRoot = new ExpandoObject();
dynamic DinLevel1 = new ExpandoObject();
dynamic DinLevel2 = new ExpandoObject();
dynamic DinLevel3 = new ExpandoObject();
dinRoot.DinLevel1 = DinLevel1;
dinRoot.DinLevel1.DinLevel2 = DinLevel2;
//dinRoot.DinLevel1.DinLevel2.DinLevel3 = DinLevel3; // You can comment this line to test
if (dinRoot?.DinLevel1?.DinLevel2?.DinLevel3 != null)
{
// Obviously it will raise an exception because the DinLevel3 does not exists, it is commented right now.
}
Is there a way to simulate this behaviour with dynamics? I mean, check for a null in a long chain of members?
If you want to support this in a more natural way you can inherit from DynamicObject and provide a custom implementation:
class MyExpando : DynamicObject
{
private readonly Dictionary<string, object> _dictionary = new Dictionary<string, object>();
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
var name = binder.Name.ToLower();
result = _dictionary.ContainsKey(name) ? _dictionary[name] : null;
return true;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_dictionary[binder.Name.ToLower()] = value;
return true;
}
}
Testing:
private static void Main(string[] args)
{
dynamic foo = new MyExpando();
if (foo.Boo?.Lol ?? true)
{
Console.WriteLine("It works!");
}
Console.ReadLine();
}
The output will be "It works!". Since Boo does not exist we get a null reference so that the Null Conditional Operator can work.
What we do here is to return a null reference to the output parameter of TryGetMember every time a property is not found and we always return true.
EDIT: fixed, as ExpandoObjects and extension methods do not work well together. Slightly less nice, but hopefully still usable.
Helper method(s):
public static class DynamicExtensions
{
public static Object TryGetProperty(ExpandoObject obj, String name)
{
return name.Split('.')
.Aggregate((Object)obj, (o, s) => o != null
? TryGetPropertyInternal(o, s)
: null);
}
private static Object TryGetPropertyInternal(Object obj, String name)
{
var dict = obj as IDictionary<String, Object>;
return (dict?.ContainsKey(name) ?? false) ? dict[name] : null;
}
}
Usage:
if (DynamicExtensions.TryGetProperty(dinRoot, "DinLevel1.DinLevel2.DinLevel3") != null)
So I am writing a C# application, using .net/c# 4.0
I have a method which takes in a custom type and a dictionary.
I reuse this for a variety of things but for some reason I cannot think of a way to encapsulate the logic. The problem is this line
if (FastIntParse.FastParse(_dict[_Rule.Key].hourly_data[a].PropertyA) >
_Rule.Value)
In another use it may be
if (FastIntParse.FastParse(_dict[_Rule.Key].hourly_data[a].PropertyB) >
_Rule.Value)
The only thing that varies in the various cases is the Property I am using to compare to the rule value. For some reason I cannot think of a way to reuse it because I don't have the value to pass in to some function since the value is derived IN the function. How can I write a function to abstract away it's need to know which value it needs to derive and pass that information in ie pass it which property it will need to check and not the value of said property.
int a;
for (int z= 0;z<=2;z++)
{
a = (z * z) * 24;
for (; (a%24) <= _Rule.AlertEndTime; a++)
{
if (FastIntParse.FastParse(_dict[_Rule.Key].hourly_data[a].PropertyA) >
_Rule.Value)
{
EnqueueRuleTrigger(_Rule);
break;
}
}
}
I keep rewriting this method inline wherever I need it with the proper property.... this is obviously quite wasteful and any change needs to be made in many places.
Thanks in advance
You can use an Expression and then pull out the property within the method, then use reflection to tie this up to the object within the method
class Program
{
static void Main(string[] args)
{
List<PropertyBag> bags = new List<PropertyBag>()
{
new PropertyBag() {Property1 = 1, Property2 = 2},
new PropertyBag() {Property1 = 3, Property2 = 4}
};
Runme(x => x.Property1, bags);
Runme(x => x.Property2, bags);
Console.ReadLine();
}
public static void Runme(Expression<Func<PropertyBag, int>> expression, List<PropertyBag> bags)
{
var memberExpression = expression.Body as MemberExpression;
var prop = memberExpression.Member as PropertyInfo;
bags.ForEach( bag =>
Console.WriteLine(prop.GetValue(bag, null))
);
}
}
public class PropertyBag
{
public int Property1 { get; set; }
public int Property2 { get; set; }
}
}
to solve the problem with access to different properties and with the use of different boolean-function (<, >, ==) you could use delegates like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace ConsoleApplication1
{
delegate bool CompareFunction(Fii test, Foo item);
class Program
{
static List<Foo> list = new List<Foo>() {
new Foo() { PropertyA = 0, PropertyB = 9 },
new Foo() { PropertyA = 1, PropertyB = 10 }
};
static Fii test = new Fii() { PropertyA = 1 };
static void Main(string[] args)
{
Bar(list, delegate(Fii item1, Foo item2) { return item2.PropertyA < item1.PropertyA; });
Bar(list, delegate(Fii item1, Foo item2) { return item2.PropertyB > item1.PropertyA; });
Bar(list, delegate(Fii item1, Foo item2) { return item2.PropertyA == item1.PropertyA; });
Console.ReadLine();
}
static void Bar(List<Foo> list, CompareFunction cmp)
{
foreach (Foo item in list)
if (cmp(test, item))
Console.WriteLine("true");
else
Console.WriteLine("false");
}
}
class Foo
{
public int PropertyA { get; set; }
public int PropertyB { get; set; }
}
class Fii
{
public int PropertyA { get; set; }
}
}
Make your function take a lambda argument and pass it _ => _.PropertyA, _ => _.PropertyB etc.:
void CheckAndEnqueueRulesByProperty (Func<YourObject, string> propertyGetter)
{
...
if (FastIntParse.FastParse (propertyGetter (
_dict[_Rule.Key].hourly_data[a])) > _Rule.Value)
{
...
}
...
}
If you have many types of objects to check with the same logic, make this function generic.
if I'm passing in a string column name, how do I call a distinct list of items by property name?
private myEntities db = new myEntities();
...
//function passes in string
var vals = db.myEntityClass
.Select(v => v.????).Distinct() //I want this to be selected dynamically
If you are using .NET 4.0, here's a post by David Fowler that makes use of the new dynamic type feature to create a DynamicQueryable and DynamicExpressionBuilder which allows you to reference entity properties dynamically.
Or.. if you rather get straight to it, he's also created a library http://bitbucket.org/dfowler/dynamiclinq the encapsulates the functionality. It's also on NuGet :)
One thing you can do is use an extension method to get the property I wrote a quick example but you will need to add additional sanity checks for your data but this is the base case.
static class BadIdea
{
public static Typ GetValue<Typ>(this object o, string PropName)
{
Type T = o.GetType();
Typ ret = default(Typ);
System.Reflection.PropertyInfo pi = T.GetProperty(PropName);
if (pi != null)
{
object tempRet = pi.GetValue(o, new object[] { });
ret = (Typ)Convert.ChangeType(tempRet, ret.GetType());
}
else
{
return default(Typ);
}
return ret;
}
public class Tst
{
public int A { get; set; }
public int B { get; set; }
}
static void Main(string[] args)
{
List<Tst> vals =new List<Tst>() { new Tst() { A = 4, B = 6 }, new Tst() { A = 4, B = 7 } };
var lst = vals.Where((x) => x.GetValue<int>("A") == 4);
foreach (Tst ot in lst)
{
Console.WriteLine("A : {0} ; B: {1}", ot.A, ot.B);
}
}
You can try this
(p => p.GetType().GetProperty(exp).GetValue(p, null)).ToString();
I think I have a fundamental misunderstanding here. Why does the test fail?
public static class ObjectExtensions
{
public static Action To<T>(this T newValue, T oldValue) where T : class
{
return () => oldValue = newValue;
}
}
public static class Assign
{
public static T TheValue<T>(T theValue)
{
return theValue;
}
}
public class Tests
{
public void Test()
{
var a = new TestType { Name = "a" };
var b = "b";
Assign.TheValue(b).To(a.Name)();
Assert.That(a.Name == "b"); //fails (a.Name == "a")
}
}
public class TestType { public string Name {get;set;} }
It fails because the arguments to To are passed by value.
Just because oldValue is set to "b" doesn't mean that a.Name will be changed at all. In the call To(a.Name), the expression a.Name is evaluated to a string reference, and that reference is passed to the method by value.
That's basic parameter passing in C#. Just using a closure doesn't change that.
What you can do is change the To method like this:
public static Action To<T>(this T newValue, Action<T> setter) where T : class
{
return () => setter(newValue);
}
then change the call to:
Assign.TheValue(b).To(x => a.Name = x)();
Put another way,
var a = new TestType { Name = "a" };
Assign.TheValue(b).To(a.Name)();
is equivalent to
Assign.TheValue(b).To("a")();
just like
int x = 5;
Convert.ToDecimal(x);
is equivalent to
Convert.ToDecimal(5);
Is it possible to have a DynamicObject implementation that can be called in chain keeping a null reference to end if anywhere in the path a null reference is encountered, without throwing any exceptions?
a.b.c.e
for example: if a is null then a.b.c.e is null, or if c is null c.e is null etc.?
Very much like the Maybe monad from Haskell.
You can do something like that, but not for the outermost object, i.e. if a is null, you can't access a.b.
You can make an empty instance of the A class, that returns empty instances for all it's properties. Then a.b would return an empty instance of B, which for the c property would return an empty instance of C, which for the e property would return an empty instance of E.
You would not get a null value, but you would get an empty instance, which you could check with:
E e = a.b.c.e;
if (e != E.Empty) { ... }
If any of the properties along the way returns an empty instance, the end result would be E.Empty.
public class A {
public B b;
public A(B newB) { b = newB; }
private static A _empty = new A(B.Empty);
public static A Empty { get { return _empty; }}
}
public class B {
public C c;
public B(C newC) { c = newC; }
private static B _empty = new B(C.Empty);
public static B Empty { get { return _empty; } }
}
public class C {
public E e;
public C(E newE) { e = newE; }
private static C _empty = new C(E.Empty);
public static C Empty { get { return _empty; } }
}
public class E {
public string name;
public E(string newName) { name = newName; }
private static E _empty = new E(null);
public static E Empty { get { return _empty; } }
}
Example:
A a1 = new A(new B(new C(new E("Hello world!"))));
A a2 = new A(new B(new C(E.Empty)));
A a3 = new A(B.Empty);
E e1 = a1.b.c.e; // e1.name returns "Hello world!"
E e2 = a2.b.c.e; // e2 == E.Empty
E e3 = a3.b.c.e; // e3 == E.Empty
Check this great article: Chained null checks and the Maybe monad
A great many programmers have met a situation where, while accessing a nested object property (e.g., person.Address.PostCode), they have to do several null checks. This requirement frequently pops up in XML parsing where missing elements and attributes can return null when you attempt to access them (and subsequently trying to access Value throws a NullReferenceException). In this article, I’ll show how a take on the Maybe monad in C#, coupled with use of extension methods, can be used to improve readability.
Here is a poor man's safe navigation extension method that just wraps an expression in a try catch looking for a nullref.
https://gist.github.com/1030887
public static class Extensions
{
public static TResult SafeInvoke<TModel, TResult>(this TModel model, Func<TModel, TResult> expression, TResult nullValue = default(TResult))
{
try
{
return expression(model);
}
catch (NullReferenceException)
{
return nullValue;
}
}
}
You can invoke the code fairly easily.
public class MyModel
{
public Name Name { get; set; }
}
public class Name
{
public string First { get; set; }
public string Last { get; set; }
}
var model = new MyModel();
var firstName = model.SafeInvoke(x => x.Name.First, "john");
var lastName = model.SafeInvoke(x => x.Name.Last, "doe");
Console.WriteLine("{0}, {1}", lastName, firstName)
// prints: "doe, john"