How to set multiple properties using Lambda in Action delegate - c#

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

Related

How do I loop through all fields in an object in C#?

I have an object like this:
public class Filters {
public int var1 = 1,
var2 = 2,
var3 = 3;
}
I declare this object here:
Filters filter1 = new Filters();
And I want to access var1, var2, and var3 in a loop and do something with it. i.e.:
foreach (var prop in filter1.props) {
Console.WriteLine(filter1[prop] + 3);
}
and the output would be:
4
5
6
I imagine I need to do a foreach loop for each property using
foreach(PropertyInfo p in filter1.GetType().GetProperties()), but I don't know how to 1) loop through props var1, var2, var3, and 2) how to subset the prop from filter1 using the name stored in the variable
If you describe your variable as properties like bellow,
public class Filters
{
public int var1 { get; set; } = 1;
public int var2 { get; set; } = 2;
public int var3 { get; set; } = 3;
}
You can access these properties with
GetType().GetProperties()
then the main method will give you what you ask for
static void Main(string[] args)
{
Filters filter1 = new Filters();
foreach (var prop in filter1.GetType().GetProperties())
{
Console.WriteLine("{0}={1}", prop.Name, (int)prop.GetValue(filter1, null) + filter1.GetType().GetProperties().Length);
}
Console.ReadKey();
}
Result will be
4
5
6
Thanks to everyone who answered-- a couple hints helped me get there. I just started in C# so I didn't know what fields/props were, so thanks #SeM #John. But with that, and with answers by #Icepickle & #arslanaybars with GetProperties() but for fields instead:
FieldInfo[] fields = typeof(GeneralFilters).GetFields();
for (int i = 0; i < fields.Length; i++)
{
//MANIPULATE HERE
BlankTemplate tempFilter = (BlankTemplate)fields[i].GetValue(filters);
// Ignore this for now. tempFilter.selectedItems;
}
where BlankTemplate is defined here:
public class BlankTemplate
{
public string[] selectedItems;
public bool selectAll = false;
}
And now in tempFilter I have the object that I need to use at every iteration
Thanks!!!
Edit: I realize that this doesn't answer the question of how to subset using the stringified name of the object fields. What I envisioned before is generating array of field names, then looping through and subsetting the data in the fields using the field names, like in javascript:
var fieldNames = Object.keys(filterObject);
for (var i = 0; i < fieldNames.length; i++) {
doSomething( filterObject[fieldNames[i]] );
}
But it seems to be a bit different in C#
An alternative answer to your question could be the following, say you have a class of filters like the following
public class Filter
{
public IDictionary<string, object> Properties { get; } = new Dictionary<string, object>();
}
This would allow you to have a dynamic set of filters, you can assign new properties as a consumer and iterate the existing ones. That seems to fit your current requirements.
As for a real answer, as many in the comments have pointed out, if you want to iterate properties, then you should actually use them. In your sample code, you have provided fields instead.
So your class Filter would probably end up looking like this (note that I think var1...var3 are the most horrible names you can use as I cannot imagine what they might define in the end):
public class Filter
{
public int Var1 { get; set; } = 1;
public int Var2 { get; set; } = 2;
public int Var3 { get; set; } = 3;
}
and then you could have something similar like:
var filter = new Filter();
var filterType = filter.GetType();
var readableProperties = filterType.GetProperties().Where( p => p.GetGetMethod() != null );
foreach (var property in readableProperties)
{
var value = (int)property.GetValue( filter );
Console.WriteLine( $"{property.Name} = {value + 3}" );
}
To ensure that you only select those you actually want, you can ofcourse check the name if it equals to Var1, Var2, Var3 or matches a regex expression, or whatever you like to think of ;)
A sample of the code here, you can find in this dotnetfiddle (though without autoproperties and $)

Cosmos DB - Use ARRAY_CONTAINS in LINQ

I have collection of documents in Cosmos DB. Document can have inner array of objects. So model look like this:
public class Document
{
public string Id { get; set; }
public IList<InnerDocument> InnerDocuments { get; set; }
}
public class InnerDocument
{
public string Type { get; set; }
public string Created { get; set; }
}
I need to get all inner documents if at least one of them has certain type.
If I create query like this:
var innerDocument = new InnerDocument()
{
Type = "foo"
};
context.CreateDocumentQuery<Document>(uri, feedOptions)
.Where(d => d.id == "sample" && d.InnerDocuments.Contains(innerDocument));
it translate like this:
SELECT * FROM root
WHERE (root[\"id\"] = "sample"
AND ARRAY_CONTAINS(root[\"innerDocuments\"], {\"type\":\"foo\"}))
but it returns nothing, because no inner document look like this (all inner documents has also Created) so I need to add third parameter to ARRAY_CONTAINS (which tell that only part match on document is enough) so it should look like this:
SELECT * FROM root
WHERE (root[\"id\"] = "sample"
AND ARRAY_CONTAINS(root[\"innerDocuments\"], {\"type\":\"foo\"}, true))
My problem is that I did not figure out how to pass third parameter in linq. I also tried write IEqualityComparer, which always return true but with no effect (well efect was that I got exception..).
Do you have any idea how could I pass that param in linq?
Thanks.
as far as I know, unfortunately there is no LINQ equivalent for the ARRAY_CONTAINS (<arr_expr>, <expr> , bool_expr) overload. To achieve your scenarios, for now you can use SQL query. We are currently working on a set of changes that will enable LINQ for this scenario.
Edit: the available alternative is to use the Any operator with the filters on the property you want to match. For example, the SQL filter: ARRAY_CONTAINS(root.addresses, {"city": "Redmond"}, TRUE) is equivalent to this LINQ expression: addresses.Any(address => address.city == "Redmond")
If I understand correctly, you wish to retrieve all documents that have any inner document in the array with a given property value ("foo" in this example).
Normally, you would use .Where(d => d.InnerDocuments.Any(i => i.Type == "foo")), but Any is not supported yet by the Cosmos LINQ provider.
Instead, you can use this construct as a work-around:
context.CreateDocumentQuery<Document>(uri, feedOptions)
.Where(d => d.Id == "sample")
.SelectMany(d => d.InnerDocuments.Where(i => i.Type == "foo").Select(i => d));
According to this thread Microsoft has recently started working on a real Any feature for the Cosmos LINQ provider.
My solution was slightly more of a hack than a solution, but it works temporarily until the full functionality for .Any() exists.
I use Expressions to dynamically build the Where predicate for my documents, allowing me pass in a CosmosSearchCriteria object which has a list of CosmosCriteria objects as below:
public class CosmosCriteria
{
public CosmosCriteria()
{
ContainsValues = new List<string>();
}
public CosmosCriteriaType CriteriaType { get; set; }
public string PropertyName { get; set; }
public string PropertyValue { get; set; }
public ConvertedRuleComparitor Comparitor { get; set; }
public DateRange Dates { get; set; }
public List<string> ContainsValues { get; set; }
}
This allows me to query any property of the Contact model by essentially passing in the PropertyName and PropertyValue.
I haven't looked into the other workaround in here to see if I can make it work with my expression tree building, at the minute I can't afford the time to investigate.
public async Task<CosmosSearchResponse<Model.Contact>>
GetContactsBySearchCriteriaAsync(int pageSize, long companyId,
CosmosSearchCriteria searchCriteria, string continuationToken = null)
{
var collectionName = CreateCollectionName(companyId, Constants.CollectionType.Contacts);
var feedOptions = new FeedOptions { MaxItemCount = pageSize };
if (!String.IsNullOrEmpty(continuationToken))
{
feedOptions.RequestContinuation = continuationToken;
}
var collection = UriFactory.CreateDocumentCollectionUri(
Configuration.GetValue<string>(Constants.Settings.COSMOS_DATABASE_SETTING),
collectionName);
IOrderedQueryable<Model.Contact> documents = Client.CreateDocumentQuery<Model.Contact>(
collection,
feedOptions
);
documents = (IOrderedQueryable<Model.Contact>)documents.Where(document => document.deleted != true);
bool requiresConcatenation = false;
foreach (var criteria in searchCriteria.Criteria)
{
switch (criteria.CriteriaType)
{
case Constants.CosmosCriteriaType.ContactProperty:
// This is where predicates for the documents.Where(xxxx)
// clauses are built dynamically with Expressions.
documents = AddContactPropertyClauses(documents, criteria);
break;
case Constants.CosmosCriteriaType.PushCampaignHistory:
requiresConcatenation = true;
break;
}
}
documents = (IOrderedQueryable<Model.Contact>)documents.AsDocumentQuery();
/*
From this point onwards, we have to do some wizardry to get around the fact that there is no Linq to SQL
extension overload for the Cosmos DB function ARRAY_CONTAINS (<arr_expr>, <expr> , bool_expr).
The feature is planned for development but is not yet ready.
Keep an eye on the following for updates:
https://stackoverflow.com/questions/52412557/cosmos-db-use-array-contains-in-linq
https://feedback.azure.com/forums/263030-azure-cosmos-db/suggestions/11503872-support-linq-any-or-where-for-child-object-collect
*/
if (requiresConcatenation)
{
var sqlString = documents.ToString();
var jsonDoc = JsonConvert.DeserializeObject<dynamic>(sqlString); // Have to do this to remove the escaping
var q = (string)jsonDoc.query;
var queryRootAlias = Util.GetAliasNameFromQuery(q);
if (queryRootAlias == string.Empty)
{
throw new FormatException("Unable to parse root alias from query.");
}
foreach (var criteria in searchCriteria.Criteria)
{
switch (criteria.CriteriaType)
{
case Constants.CosmosCriteriaType.PushCampaignHistory:
q += string.Format(" AND ARRAY_CONTAINS({0}[\"CampaignHistory\"], {{\"CampaignType\":1,\"CampaignId\":{1}, \"IsOpened\": true }}, true) ", queryRootAlias, criteria.PropertyValue);
break;
}
}
documents = (IOrderedQueryable<Model.Contact>)Client.CreateDocumentQuery<Model.Contact>(
collection,
q,
feedOptions
).AsDocumentQuery();
}
var returnValue = new CosmosSearchResponse<Model.Contact>();
returnValue.Results = new List<Model.Contact>();
Console.WriteLine(documents.ToString());
var resultsPage = await ((IDocumentQuery<Model.Contact>)documents).ExecuteNextAsync<Model.Contact>();
returnValue.Results.AddRange(resultsPage);
if (((IDocumentQuery<Model.Contact>)documents).HasMoreResults)
{
returnValue.ContinuationToken = resultsPage.ResponseContinuation;
}
return returnValue;
}
Hope this helps, or if someone has a better way, please do tell!
Dave

How can I get NHibernate to map to a custom Class?

I actually asked a very similar question recently, but while the title mentioned classes, my content mostly referred to a tuple, and the (really great) answer reflected that. When I've tried to substitute a class in for the tuple, I get TargetParameterCountException: Parameter count mismatch. exception.
How can I get NHibernate to map to a Tuple or Class?
I have the following method to get a list of results from the database.
public static IList<T> Find<T>(DetachedCriteria crit) where T : class
{
lock (_locker)
{
return crit.GetExecutableCriteria(InstanceSession)
.List<T>();
}
}
This generally works well. However, I've changed a method that calls the method above from.
public IList<FooBarResult> FindResults(FooBarTask st)
{
return DataAccess.Find<FooBarResult>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))).ToList();
}
Which works, to this (as I don't want to return the whole of FooBarResult, just certain columns on it).
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(
Projections.Property("FieldOne") //this is a DateTime
)
.Add(
Projections.Property("FieldTwo") //this is a Guid
)
.SetResultTransformer(Transformers.AliasToBeanConstructor(typeConstructor))
)
);
}
And this is the class.
public class MyCustomClass
{
public MyCustomClass()
{
//placeholder
}
public MyCustomClass(DateTime FieldOne, Guid FieldTwo)
{
this.FieldOne = FieldOne;
this.FieldTwo = FieldTwo;
}
public DateTime FieldOne { get; set; }
public Guid FieldTwo { get; set; }
}
As mentioned earlier, when running the return crit.GetExecutableCriteria(InstanceSession).List<T>(); code I get a TargetParameterCountException: Parameter count mismatch. exception.
Is there any way I can make it return a list of my MyCustomClass?
I have not tested this, but you should use Transformers.AliasToBean take a look in to the aliases to let the transformer work:
public IList<MyCustomClass> FindResults(FooBarTask st)
{
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
return DataAccess.Find<MyCustomClass>(DetachedCriteria.For<FooBarResult>()
.Add(Restrictions.Eq("Task", st))
.SetProjection(
Projections.ProjectionList()
.Add(Projections.Property("FieldOne"), "FieldOne")
.Add(Projections.Property("FieldTwo"), "FieldTwo")
)
.SetResultTransformer(Transformers.AliasToBean(typeof(MyCustomClass)))
.List<MyCustomClass>()
}
In this line:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[0];
you will get the first, default constructor and its signature obviously doesn't match. The simplest fix for your case is:
var typeConstructor = typeof(MyCustomClass).GetConstructors()[1];
But the cleanest solution would be something along these lines (untested and also a bit simplified):
var typeConstructor = GetMatchingConstructorOrThrow<MyCustomClass>
(typeof(DateTime), typeof(Guid));
// ...
private ConstructorInfo GetMatchingConstructorOrThrow<T>(params Type[] requiredSignature)
where T : class
{
foreach (var c in typeof(T).GetConstructors())
{
var currentSignature = c.GetParameters().Select(p => p.ParameterType);
if (currentSignature.SequenceEqual(requiredSignature))
{
return c;
}
}
throw new NoMatchingConstructorFoundException();
}

For loop to add image to imagelist

I'm cleaning up my code trying to short in some things
Now I've stumbled across:
ImageList.Add(test.Properties.Resources.test1);
ImageList.Add(test.Properties.Resources.test2);
ImageList.Add(test.Properties.Resources.test3);
ImageList.Add(test.Properties.Resources.test4);
ImageList.Add(test.Properties.Resources.test5);
(There are 15 of these)
Was wondering if this could be shortened with a for loop
Something like:
for(int i=1; i<=15; i++)
ImageList.Add(test.Properties.Resources.test +i);
Now ofcourse this won't work but I have no clue how to do this (if even possible)
You can iterate over resources via this code
using System.Collections;
using System.Globalization;
using System.Resources;
...
ResourceSet resourceSet = MyResourceClass.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
foreach (DictionaryEntry entry in resourceSet)
{
string resourceKey = entry.Key;
object resource = entry.Value;
}
You can use reflection, to get the values:
public class Something
{
public int Test1 { get; set; }
public int Test2 { get; set; }
public int Test3 { get; set; }
public int Test4 { get; set; }
}
var thing = new Something();
var imageProperties = typeof(Something)
.GetProperties()
.Where(p => p.Name.StartsWith("Test"));
var imagesToAdd = imageProperties
.Select(property => property.GetValue(thing))
.ToList();
You could define a property of type IEnumerable<Image> in the class of Resources object
public IEnumerable<Image> Images
{
get
{
yield return test1;
yield return test2;
yield return test3;
yield return test4;
yield return test5;
...
}
}
and then use it to fill ImageList
foreach(var image in test.Properties.Resources.Images)
{
ImageList.Add(image);
}
I just found out that there is a library for evaluating C# expression called Flee. Apparently you can use it to evaluate C# code so that you can loop over variable names, just like JavaScript, but the need for it most likely means a design flaw.
http://flee.codeplex.com/

How do I dynamically apply a conditional operator to a field using the official MongoDB-CSharp-Driver?

I'm trying to generate a query that finds all large, red things with a cost greater than 3.
This query seems to be what I'm after:
{ "color" : "red", "size" : "large", "cost" : { "$gt" : 3.0 } }
But, I am unable to find an elegant way to create the cost condition using the official MongoDB CSharp Driver. This is one hack which seems to create the query:
QueryConditionList gt = Query.GT("cost", BsonDouble.Create(3));
QueryDocument query = new QueryDocument();
query.Add("color", "red");
query.Add("size", "large");
query.Add(gt.ToBsonDocument().Elements);
List<BsonDocument> results = events.Find(query).ToList();
Another way to do it which seems to work is like this:
QueryDocument query = new QueryDocument();
query.Add("color", "red");
query.Add("size", "large");
query.Add("cost", new BsonDocument("$gt", BsonDouble.Create(3)));
List<BsonDocument> results = events.Find(query).ToList();
Are either of these approaches a good way to accomplish this? Is there another?
I need to use techniques which allow me to dynamically build the query and add fields that will be involved in the query. I was hoping to find a way to add a condition via query.Add( ) but I don't know if that is possible.
Any help is appreciated.
You can use the Query builder throughout, like so:
var query = Query.And(
Query.EQ("color", "red"),
Query.EQ("size", "large"),
Query.GT("cost", 3)
);
update Sorry, I see what you're asking, now.
You could do something like this, also:
int i = 0;
var qc = QueryComplete[3];
qc[i++] = Query.EQ("color", "red");
qc[i++] = Query.EQ("size", "large");
qc[i++] = Query.GT("cost", 3);
var query = Query.And(qc);
This way, you can still use the builder methods and have it be dynamic.
You can data drive it in a brute force manner, just build a tree of "QueryElement" and call BuildQuery to recursively build it as in this example class:
public class QueryElement
{
public enum eOperator
{
AND, OR, EQ, NE, GT, GTE, LT, LTE //etc.
};
public eOperator Operator { get; set; }
public string Field { get; set; }
public BsonValue Value { get; set; }
public List<QueryElement> Children { get; set; }
public IMongoQuery BuildQuery()
{
int i = 0;
var qc = new IMongoQuery[(Children!=null)?Children.Count:0];
if (Children != null)
{
foreach (var child in Children)
{
qc[i++] = child.BuildQuery();
}
}
switch (Operator)
{
// multiple element operators
case eOperator.AND:
return Query.And(qc);
case eOperator.OR:
return Query.And(qc);
// single element operators
case eOperator.EQ:
return Query.EQ(Field, Value);
case eOperator.NE:
return Query.NE(Field, Value);
case eOperator.GT:
return Query.GT(Field, Value);
case eOperator.GTE:
return Query.GTE(Field, Value);
case eOperator.LT:
return Query.LT(Field, Value);
case eOperator.LTE:
return Query.LTE(Field, Value);
}
return null;
}
}

Categories

Resources