Using lambda for builder pattern - c#

The telerik grid uses lambda syntax to enhance the builder patter when binding to columns.
.Columns(cols =>
{
cols.Bound(e => e.Tag);
cols.Bound(e => e.Name);
});
I would like to make a similar function in my code. I already have the syntax for the Bound() function down. But what would the syntax for the Columns() function look like?
Here is a better example of what I am trying to accomplish:
class SubList
{
private List<string> _items;
public AddItem(string item)
{
_items.Add(item);
}
}
class MyCollections
{
private Dictionary<string, SubList> _subs = new Dictionary<string,SublList>();
public SubList AddList(string name)
{
var newSub = new SubList();
_subs[name] = newSub;
return newSub;
}
}
class Other
{
public void DoStuff()
{
var collections = new MyCollections();
//if add item throws error, I don't know which one it is as.
//it is also hard to put a break point in here.
collections.AddList("one")
.AddItem("1")
.AddItem("un")
.AddItem("uno");
//I would like to have something like this:
collections.AddList("two") { s =>
s.AddItem("1");
s.AddItem("un"); //yay! can put breakpoint here
s.AddItem("uno");
};
//or perhaps
collections.AddList("two").Sub( s => {
s.AddItem("1");
s.AddItem("un"); //yay! can put breakpoint here
s.AddItem("uno");
});
}
}

It could either be an extension method or an instance method, probably on the order of:
// Assuming some grid type TDataGrid and some column building type TColumnBuilder
public TDataGrid Columns(Action<TColumnBuilder> applyColumns)
{
// Ask the user what they'd like to do with our columns
TColumnBuilder placeholder = new TColumnBuilder();
applyColumns(placeholder);
// do something with what we've learned
// this.columns = placeholder.CreateColumns();
}

Related

how to use ready-made Func<> delegate in QueryAsync?

I have such a problem that I have the same Func in my methods. I took it out separately, but now the problem is how to pass parameters to it. I want to use it in several places, but I don't know how to get the necessary parameters from the QueryAsync method
My func delegate
private Func<Authors, AuthorInPrintingEditions, PrintingEditions, Authors> _relationDelegate =
(Authors authors, AuthorInPrintingEditions relation, PrintingEditions printingEdition) =>
{
if (!_dictionaryResult.ContainsKey(authors.Id))
{
_dictionaryResult.Add(authors.Id, new Authors()
{
Id = authors.Id,
Name = authors.Name,
AuthorInPrintingEditions = printingEdition == null
? new List<AuthorInPrintingEditions>()
: new List<AuthorInPrintingEditions>()
{
new AuthorInPrintingEditions()
{
PrintingEdition = printingEdition
}
}
});
}
else
{
if (printingEdition != null)
{
_dictionaryResult[authors.Id].AuthorInPrintingEditions.Add(new AuthorInPrintingEditions()
{
PrintingEdition = printingEdition
});
}
}
return authors;
};
My method, when I want use it
using (var conneсtion = CreateConnection())
{
await conneсtion.QueryAsync<Authors, AuthorInPrintingEditions, PrintingEditions, Authors>(query,
(authors, authorInPrintingEditions, printingEdition), <--- in this row I want use delegate
new { skip = skip, pageSize = pageSize }, splitOn: "Id,AuthorId,Id");
return _dictionaryResult.Values.ToList();
}
I don't understand how to pass parameters to it and whether it is generally possible, or it will still be easier to copy and paste
If you wish to reuse the delegate and also be able to use parameters,
try using something like this:
public class AuthorsMapper
{
public int Parameter1;
public string Parameter2;
public Func<Authors, AuthorInPrintingEditions, PrintingEditions, Authors> Map =>
// Your existing code that can now use parameters
}
And use it like this:
var mapper = new AuthorsMapper
{
Parameter1 = 742,
Parameter2 = "House"
};
await conneсtion.QueryAsync<Authors, AuthorInPrintingEditions, PrintingEditions, Authors>
(query, mapper.Map, ...);

LINQ query to return collection of original object with a transformed property

I currently have working code
foreach (var item in list)
{
item.Property1= SomeFunction(item.Property1);
}
return list;
I'd like to convert this into a LINQ query but I'm not quite sure how to. I suspect I need to use a .Select but I'm not sure how to do that properly. My attempt was to try:
return list.Select(r => SomeFunction(r.Property1));
but of course that only returned a collection of Properties whereas I want a collection of the original object with an altered property within it.
I think this is probably a bad idea in general, but here you go ...
You want something like list.Select(x => { SomeFunction(x); return x; }); where SomeFunction is a function to transform the property you want.
Full example:
public class A { public int Data { get; set; } }
public void SomeFunction(A a)
{
a.Data *= 2;
}
var listy = new List<A>() {
new A() { Data = 3 },
new A() { Data = 5 }
};
listy.Select(x => { SomeFunction(x); return x; })
output (C# Interactive shell):
Enumerable.WhereSelectListIterator<Submission#9.A, Submission#9.A> { Submission#9.A { Data=6 }, Submission#9.A { Data=10 } }
Assuming list if of type List<>:
list.ForEach(x => x.Property1 = SomeFunction(item.Property1));
But what is wrong with foreach anyway?

How to set multiple properties using Lambda in Action delegate

This is probably simple, but I can't figure out how to set multiple properties in a single statement.
LCCorsOptions.cs:
public class LCCorsOptions
{
public int AppId { get; set; }
public string Version { get; set; } = "1.0";
}
This is what I got so far:
app.UseLCCors(o => o.Version = "1.0");
I've tried multiple approaches, but with no luck
This is about lambda syntax, the part on the right is a normal method body that you may shorten when it is 1 expression or 1 statement. Otherwise, use full { }and ;
app.UseLCCors(o => {o.Version = "1.0"; o.AppId = 2; });
I'm assuming you're using an extension method that's something like this:
public static void UseLCCors(this List<LCCorsOptions> list, Action<LCCorsOptions> action)
{
foreach (var item in list)
{
action(item);
}
}
If so try to put some braces after the lambda sign like this:
app.UseLCCors(x => { x.Version = "1"; x.AppId = 1; });
Is this what you've been looking for?
You probably want to give a LCCorsOptions in the initialization of your app. Can't you do something like this:
app.UseLCCors(new LCCorsOptions{Version = "1.0", AppId = 2});

Builder pattern with nested objects

Hi I'm stuck with a problem.
I want to implement the builder pattern to make creating my objects easier. The problem I face has to do with nested object. The object I would like to create has a list of other objects in it, and I don't really have an idea on how to tackle it.
I want to be able to do the following (Simpler objects for example):
Receipt RestaurantReceipt = new ReceiptBuilder()
.withDate("value")
.withName("value")
.AddItem("value")
.WithIngredients("value")
.WithType("value")
.AddItem("value")
.WithIngredients("value")
.WithType("value")
.build();
Or something like:
Receipt RestaurantReceipt = new ReceiptBuilder()
.withDate("value")
.withName("value")
.AddItem("value", item => {
.WithIngredients("value")
.WithType("value")
})
.AddItem("value", item => {
.WithIngredients("value")
.WithType("value")
})
.build();
Example should be representative for my situation, although if got more than one type of nested object.
Given code like this
var rb = new ReceiptBuilder();
var receipt = rb.WithName("Name")
.WithDate(DateTime.Now)
.WithItem("Item1", i => i.WithIngredients("Ingredients1"))
.WithItem("Item2", i => i.WithIngredients("Ingredients1"))
.Build();
Console.WriteLine(receipt);
Your builder is pretty simple, making use of some simple predicates inside the WithItem builder method to allow the consumer to configure each item in a similar "builder" pattern to the top level ReceiptBuilder:
public class ReceiptBuilder
{
private Receipt r;
public ReceiptBuilder()
{
r = new Receipt();
}
public ReceiptBuilder WithName(string name)
{
r.Name = name;
return this;
}
public ReceiptBuilder WithDate(DateTime dt)
{
r.Date = dt;
return this;
}
public ReceiptBuilder WithItem(string text, Action<ReceiptItemBuilder> itemBuilder)
{
var rib = new ReceiptItemBuilder(text);
itemBuilder(rib);
r.AddItem(rib.Build());
return this;
}
public Receipt Build()
{
return r;
}
}
public class ReceiptItemBuilder
{
private ReceiptItem ri;
public ReceiptItemBuilder(string text)
{
ri = new ReceiptItem(text);
}
public ReceiptItemBuilder WithIngredients(string ings)
{
ri.Ingredients = ings;
return this;
}
// WithType omitted for brevity.
internal ReceiptItem Build()
{
return ri;
}
}
Working example: http://rextester.com/IRR50897

How to set one ObservableCollection to another ObservableCollection?

Basically, I want to know if I can do this with two ObservableCollections:
oldList = newList;
I have two lists that get populated throughtout my app, and each time they get populated, I want the 'new' values to become the 'old' values, and then get a new set of values to put in the 'new' list.
is it that easy? Any other way to do this without iterating over the whole newList every time?
EDIT: This is how the new list is being populated. Basically, I just want the contents of the newList to be put into the oldList.
foreach (object obj in ts.GetVariables())
{
if ((obj.ToString() != "_SMSTSReserved2") || (obj.ToString() != "OSDJoinPassword") || (obj.ToString() != "OSDLocalAdminPassword"))
{
TSVar var = new TSVar();
var.TSVarName = obj.ToString();
var.TSVarValue = ts[obj.ToString()];
newList.Add(var);
}
}
oldList.Clear();
foreach (TSVar var in newList)
{
oldList.Add(var);
}
If you use the extension method listed below, what you are trying to do becomes a one liner:
oldList.Replace(newList);
I would create an Extension Method for ObservableCollection like this:
public static class ObservableCollectionExtensionMethods
{
public static void Replace<T>(this ObservableCollection<T> old, ObservableCollection<T> #new)
{
old.Clear();
foreach (var item in #new)
{
old.Add(item);
}
}
}
And this is how you would use it:
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ExtensionMethods
{
[TestClass]
public class ObservableCollectionExtensionMethodsTest
{
[TestMethod]
public void ReplaceTest()
{
// Arrange
var old = new ObservableCollection<string> { "1"};
var #new = new ObservableCollection<string> {"2"};
// Act
old.Replace(#new);
// Assert
Assert.AreEqual("2", old.First());
}
}
}
I think this is what you may be looking for? This will add everything that was in newList to your oldList.
ObservableCollection<YourType> oldList = new ObservableCollection<YourType>(newList);
newList.clear();
//put new stuff in your list here.

Categories

Resources