Calling IF Statement method in C# - c#

I have noticed that I am repeating a lot of my code. What I want to do is store the below if-statement in a method so that it can be called at any time. My problem is, I understand methods, slightly, but I'm having difficulty creating a method for what i want. Below is an example of my code. The commented out code is the code i want to put in a method.Any help is much appreciated.
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
/*if (titleTokens.Contains(s))
{
MessageBox.Show("");
}
else
{
MessageBox.Show("");
}*/
}

private bool Check(string result, string type) {
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
return titleTokens.Contains(s);
}
return false;
}
You mean like this ?

//To call the function use the following line and replace yourClassName with you class name
yourClassName myInstObj= new yourClassName();
myInstObj.Check(result,type);
//Copied from the above answer b/c it should work fine.
private bool Check(string result, string type) {
if (result.Equals("") && type == "")
{
JObject jobj = JObject.Parse(Helper.callerClass(#""));
var titleTokens = jobj.SelectTokens("...title");
var values = titleTokens.Select(x => (x as JProperty).Value);
if (titleTokens.Contains(s))
{
return true;
}
else
{
return false;
}
}
}

Related

C# - Compare two strings by using dots in the strings and using wildcards: *

I have two string variables that i want to compare.
var compareA = "something.somethingelse.another.something2"
var compareB = "*.another.something2"
I want to compare this, and the result is: True.
var compareC = "something.somethingelse.*"
compared to compareA, the result should also be: True.
Of course, the fact that both variables can contain N dots also complicates the task.
How would you start for him?
I was tried this:
static void Main(string[] args)
{
var A = CompareString("*.something", "other.Another.something"); //I need this is true!
var B = CompareString("something.Value.Other.*", "something.Value.Other.SomethingElse"); //I need this is true
var C = CompareString("something.Value.Other", "something.Value.Other.OtherElse"); //I need this is False
var D = CompareString("*.somethingElse", "other.another.Value"); //I Need this is false
Console.WriteLine("It is need True: {0}", A);
Console.WriteLine("It is need True: {0}", B);
Console.WriteLine("It is need False: {0}", C);
Console.WriteLine("It is need False: {0}", D);
}
private static bool CompareString(string first, string second)
{
var resume = false;
var firstSplit = first.Split('.');
var secondSplit = second.Split('.');
foreach (var firstItem in firstSplit)
{
foreach (var secondItem in secondSplit)
{
if (firstItem == "*" || secondItem == "*" || string.Equals(firstItem.ToLower(), secondItem.ToLower()))
{
resume = true;
}
else
{
resume = false;
}
}
}
return resume;
}
The results are good, but I think it can be done differently, and the reasoning may be wrong.
Assuming the following:
Compare 1 string to another and it's the full string of 1 contained inside the longer of the 2 strings.
Case to be ignored as well as culture.
The full stops are considered part of the string, not actually as a separator.
Wildcards can be used to state how 1 string can be contained within another.
You should be able to use the following
private bool HasMatch(string textToSearch, string searchText)
{
if (textToSearch.Length < searchText.Length) return false;
var wildCardIndex = searchText.IndexOf('*');
if (wildCardIndex == -1)
{
return textToSearch.Equals(searchText, StringComparison.InvariantCultureIgnoreCase);
}
else
{
if (wildCardIndex == 0)
{
var text = searchText.TrimStart('*');
return textToSearch.EndsWith(text, StringComparison.InvariantCultureIgnoreCase);
}
if (wildCardIndex == (searchText.Length - 1))
{
var text = searchText.TrimEnd('*');
return textToSearch.StartsWith(text, StringComparison.InvariantCultureIgnoreCase);
}
}
return false;
}

Getting expression text

I want to pass the name of a property of a model to a method. Instead of using the name as string, I am using lambda expression as it is easy to make a typo, and also property names may be changed. Now if the property is a simple property (e.g: model.Name) I can get the name from the expression. But if it is a nested property (e.g: model.AnotherModel.Name) then how can I get full text ("AnotherModel.Name") from the expression. For example, I have the following classes:
public class BaseModel
{
public ChildModel Child { get; set; }
public List<ChildModel> ChildList { get; set; }
public BaseModel()
{
Child = new ChildModel();
ChildList = new List<ChildModel>();
}
}
public class ChildModel
{
public string Name { get;set; }
}
public void GetExpressionText<T>(Expression<Func<T, object>> expression)
{
string expText;
//what to do??
return expText;
}
GetExpressionText<BaseModel>(b => b.Child); //should return "Child"
GetExpressionText<BaseModel>(b => b.Child.Name); //should return "Child.Name"
GetExpressionText<BaseModel>(b => b.ChildList[0].Name); //should return "ChildList[0].Name"
My first thought was to use expression.Body.ToString() and tweak that a bit, but you would still need to deal with Unary (convert) etc. Assuming this is for logging and you want more control, the below can be used for formatting as wanted (e.g. if you want Child->Name for display purposes, string.Join("->",..) can be used). It may not be complete, but should you find any unsupported types, they should be easy to add.
PS: this post was generated before the question was closed. Just noticed it was reopend and submitting it now, but I haven't checked if particulars have been changed.
public string GetName(Expression e, out Expression parent)
{
if(e is MemberExpression m){ //property or field
parent = m.Expression;
return m.Member.Name;
}
else if(e is MethodCallExpression mc){
string args = string.Join(",", mc.Arguments.SelectMany(GetExpressionParts));
if(mc.Method.IsSpecialName){ //for indexers, not sure this is a safe check...
return $"{GetName(mc.Object, out parent)}[{args}]";
}
else{ //other method calls
parent = mc.Object;
return $"{mc.Method.Name}({args})";
}
}
else if(e is ConstantExpression c){ //constant value
parent = null;
return c.Value?.ToString() ?? "null";
}
else if(e is UnaryExpression u){ //convert
parent= u.Operand;
return null;
}
else{
parent =null;
return e.ToString();
}
}
public IEnumerable<string> GetExpressionParts(Expression e){
var list = new List<string>();
while(e!=null && !(e is ParameterExpression)){
var name = GetName(e,out e);
if(name!=null)list.Add(name);
}
list.Reverse();
return list;
}
public string GetExpressionText<T>(Expression<Func<T, object>> expression) => string.Join(".", GetExpressionParts(expression.Body));
You could use the C# 6.0 feature: nameof(b.Child) "Used to obtain the simple (unqualified) string name of a variable, type, or member."
which will also change on renaming. But this will only return the propertyname and not the complete path. Returning a complete path will be difficult, because only one instance is passed.
Closest i know right now is by simply using expression.Body.ToString() which would result in b.ChildList.get_Item(0).Name as a result.
You would still have to remove the first b. from the string if not wanted, and you could go even further to your intended output with Regex by replacing the get_Item(0) with the typical Index-Accessor.
(Also i had to make the ChildList and the Name-Property of ChildModel public to get it to work)
This Should get you most of the way there:
public static string GetFullPath<T>(Expression<Func<T>> action)
{
var removeBodyPath = new Regex(#"value\((.*)\).");
var result = action.Body.ToString();
var replaced = removeBodyPath.Replace(result, String.Empty);
var seperatedFiltered = replaced.Split('.').Skip(1).ToArray();
return string.Join(".", seperatedFiltered);
}
It gets ugly quite quickly...
public static string GetExpressionText<T>(Expression<Func<T, object>> expression)
{
bool needDot = false;
Expression exp = expression.Body;
string descr = string.Empty;
while (exp != null)
{
if (exp.NodeType == ExpressionType.MemberAccess)
{
// Property or field
var ma = (MemberExpression)exp;
descr = ma.Member.Name + (needDot ? "." : string.Empty) + descr;
exp = ma.Expression;
needDot = true;
}
else if (exp.NodeType == ExpressionType.ArrayIndex)
{
// Array indexer
var be = (BinaryExpression)exp;
descr = GetParameters(new ReadOnlyCollection<Expression>(new[] { be.Right })) + (needDot ? "." : string.Empty) + descr;
exp = be.Left;
needDot = false;
}
else if (exp.NodeType == ExpressionType.Index)
{
// Object indexer (not used by C#. See ExpressionType.Call)
var ie = (IndexExpression)exp;
descr = GetParameters(ie.Arguments) + (needDot ? "." : string.Empty) + descr;
exp = ie.Object;
needDot = false;
}
else if (exp.NodeType == ExpressionType.Parameter)
{
break;
}
else if (exp.NodeType == ExpressionType.Call)
{
var ca = (MethodCallExpression)exp;
if (ca.Method.IsSpecialName)
{
// Object indexer
bool isIndexer = ca.Method.DeclaringType.GetDefaultMembers().OfType<PropertyInfo>().Where(x => x.GetGetMethod() == ca.Method).Any();
if (!isIndexer)
{
throw new Exception();
}
}
else if (ca.Object.Type.IsArray && ca.Method.Name == "Get")
{
// Multidimensiona array indexer
}
else
{
throw new Exception();
}
descr = GetParameters(ca.Arguments) + (needDot ? "." : string.Empty) + descr;
exp = ca.Object;
needDot = false;
}
}
return descr;
}
private static string GetParameters(ReadOnlyCollection<Expression> exps)
{
var values = new string[exps.Count];
for (int i = 0; i < exps.Count; i++)
{
if (exps[i].NodeType != ExpressionType.Constant)
{
throw new Exception();
}
var ce = (ConstantExpression)exps[i];
// Quite wrong here... We should escape string values (\n written as \n and so on)
values[i] = ce.Value == null ? "null" :
ce.Type == typeof(string) ? "\"" + ce.Value + "\"" :
ce.Type == typeof(char) ? "'" + ce.Value + "\'" :
ce.Value.ToString();
}
return "[" + string.Join(", ", values) + "]";
}
The code is quite easy to read, but it is quite long... There are 4 main cases: MemberAccess, that is accessing a property/field, ArrayIndex that is using the indexer of a single-dimensional array, Index that is unused by the C# compiler, but that should be using the indexer of an object (like the [...] of the List<> you are using), and Call that is used by C# for using an indexer or for accessing multi-dimensional arrays (new int[5, 4]) (and for other method calls, but we disregard them).
I support multidimensional arrays, jagged array s(arrays of arrays, new int[5][]) or arrays of indexable objects (new List<int>[5]) or indexable objects of indexable objects (new List<List<int>>). There is even support for multi-property indexers (indexers that use more than one key value, like obj[1, 2]). Small problem: printing the "value" of the indexers: I support only null, integers of various types, chars and strings (but I don't escape them... ugly... if there is a \n then it won't be printed as \n). Other types are not really supported... They will print what they will print (see GetParameters() if you want)

Given the object identifier, how do we read the corresponding value from a ASN.1 DER encoded binary file?

I'm trying to read the value corresponding to a object identifier, from a Microsoft security catalog (*.cat) file, which is in fact a DER encoded ASN.1 object. I am using bouncy castle to create a Asn1Object. When I perform a .ToString() I can see my data in ASCII in the dumped text, against the object identifier "1.3.6.1.4.1.311.12.2.1" but is there a way to retrieve the data specifcally by passing this OID?
I see a class Org.BouncyCastle.Asn1.Microsoft, but I am not sure how to use this class. Any help appreciated! So far I have only this, where I call File.ReadAllBytes and pass to the function I've written below, on this I can call ToString() and see all data in the .cat
private Asn1Object asn1Object(byte[] data)
{
Asn1InputStream asn1InputStream = new Asn1InputStream(data);
if(asn1InputStream != null)
{
return asn1InputStream.ReadObject().;
}
else
{
return null;
}
}
The short answer: You would need to recursively walk the tree to find the DerSequence containing the DerObjectIdentifier and then returning the DerObjectIdentifiers next sibling.
The long answer: Looking at the ASN1/DER structure, there doesn't appear to be a single entry in the object graph that has the OID and a value. It appears that for a particular OID, it will be the first child object in a DerSequence and the value will be the second child object.
A recursive method that will find the DerSequence containing the DerObjectIdentifier matching your OID and return you the next sibling is:
public static Asn1Object FindAsn1Value(string oid, Asn1Object obj)
{
Asn1Object result = null;
if (obj is Asn1Sequence)
{
bool foundOID = false;
foreach (Asn1Object entry in (Asn1Sequence)obj)
{
var derOID = entry as DerObjectIdentifier;
if (derOID != null && derOID.Id == oid)
{
foundOID = true;
}
else if (foundOID)
{
return entry;
}
else
{
result = FindAsn1Value(oid, entry);
if (result != null)
{
return result;
}
}
}
}
else if (obj is DerTaggedObject)
{
result = FindAsn1Value(oid, ((DerTaggedObject)obj).GetObject());
if (result != null)
{
return result;
}
}
else
{
if (obj is DerSet)
{
foreach (Asn1Object entry in (DerSet)obj)
{
result = FindAsn1Value(oid, entry);
if (result != null)
{
return result;
}
}
}
}
return null;
}
To call this you would load the Asn1Object using the method you provided, and then call the FindAsn1Value shown above. This should return you the Asn1Object you are after (in the case of my test cat file, this value was a DerOctetString).
Asn1Object asn = asn1Object(File.ReadAllBytes(#"test_file.cat"));
Asn1Object value = FindAsn1Value("1.3.6.1.4.1.311.12.2.1", asn);
if (value is DerOctetString)
{
UnicodeEncoding unicode = new UnicodeEncoding(true, true);
Console.WriteLine("DerOctetString = {0}", unicode.GetString(((DerOctetString)value).GetOctets()));
}
I'm not sure if the value for that OID will always be a DerOctetString nor whether my decoding choice is necessarily correct, however it gave me the most readable version of the value that my test was working with.
Update
If the same OID appears multiple times in the hierarchy and you need to return all the possible values, an alternative method could be:
public static List<Asn1Object> FindAsn1Values(string oid, Asn1Object obj)
{
Asn1Object result = null;
List<Asn1Object> results = new List<Asn1Object>();
if (obj is Asn1Sequence)
{
bool foundOID = false;
foreach (Asn1Object entry in (Asn1Sequence)obj)
{
var derOID = entry as DerObjectIdentifier;
if (derOID != null && derOID.Id == oid)
{
foundOID = true;
}
else if (foundOID)
{
results.Add(entry);
}
else
{
result = FindAsn1Values(oid, entry);
if (result.Count > 0)
{
results.AddRange(result);
}
}
}
}
else if (obj is DerTaggedObject)
{
result = FindAsn1Values(oid, ((DerTaggedObject)obj).GetObject());
if (result.Count > 0)
{
results.AddRange(result);
}
}
else
{
if (obj is DerSet)
{
foreach (Asn1Object entry in (DerSet)obj)
{
result = FindAsn1Values(oid, entry);
if (result.Count > 0)
{
results.AddRange(result);
}
}
}
}
return results;
}

Troubles with large amount of Code duplication

I have a lot of methods that follow in large parts the same algorithm, and I ideally want to be able to make calls to a generic method that eliminates a lot of code duplication.
I have tons of methods like the ones below, I would optimally want to be able to just call
Save<SQLiteLocation>(itemToSave); but i have a great deal of trouble since that the methods
SQLiteConnection.Find<T> won't accept an abstract data type like T in generics.
Is there any way to get around this, if i could get it fixed i would save as many as 150 lines of code
Here's my code:
public bool SaveLocation(ILocation location, ref int primaryKey)
{
var dbConn = new SQLiteConnection (dbPath);
SQLiteLocation itemToSave = new SQLiteLocation ();
itemToSave.LocationName = location.LocationName;
itemToSave.Latitude = location.Latitude;
itemToSave.Longitude = location.Longitude;
itemToSave.PrimaryKey = location.PrimaryKey;
----------------------------------------------------------------------------------------
SQLiteLocation storedLocation = dbConn.Find<SQLiteLocation>
(x => x.PrimaryKey == location.PrimaryKey);
if (storedLocation != null)
{
dbConn.Update(itemToSave);
return true;
}
else if (storedLocation == null)
{
dbConn.Insert(itemToSave);
primaryKey = itemToSave.PrimaryKey;
return true;
}
return false;
}
And here another method see how the code in both methods below my dashed line is basically the same thing
public bool SaveInvitation(IInvitation invitation, ref int primaryKey)
{
var dbConn = new SQLiteConnection(dbPath);
SQLiteInvitation itemToSave = new SQLiteInvitation ();
itemToSave.GroupName = invitation.GroupName;
itemToSave.InviterName = invitation.InviterName;
itemToSave.ParseID = invitation.ParseID;
itemToSave.GroupParseID = invitation.GroupParseID;
itemToSave.PrimaryKey = invitation.PrimaryKey;
---------------------------------------------------------------------------------------
SQLiteInvitation storedInvitation = dbConn.Find<SQLiteInvitation>
(x => x.PrimaryKey == invitation.PrimaryKey);
if (storedInvitation != null)
{
dbConn.Update(itemToSave);
return true;
}
else if (storedInvitation == null)
{
dbConn.Insert(itemToSave);
primaryKey = itemToSave.PrimaryKey;
return true;
}
return false;
}
Shouldn't you be able to do something like this:
Note: ICommonInterface is anything that is common between any allowable classes you would want to use as T. Preferably, looking at your code, an interface or class that exposes the PrimaryKey property.
public bool SaveItem<T>(T item, ref int primaryKey) where T : ICommonInterface, new()
{
var dbConn = new SQLiteConnection(dbPath);
T storedItem = dbConn.Find<T>(x => x.PrimaryKey == item.PrimaryKey);
if (storedItem != null)
{
dbConn.Update(item);
return true;
}
else if (storedItem == null)
{
dbConn.Insert(item);
primaryKey = item.PrimaryKey;
return true;
}
return false;
}
EDIT: Added the new() constraint to the method.
For some reason it threw an not supported exception
when i used :
T storedItem = dbConn.Find<T>(x => x.PrimaryKey == item.PrimaryKey);
The code below fixed my woes though, thanks for the help everyone, I love this site!
Also i added another constraint on T seeing as T has to be a non abstract type and an interface is just that I suppose
private void SaveItem<T>(T item, ref int primaryKey)
where T : ISQLiteClass, new()
{
var dbConn = new SQLiteConnection(dbPath);
T storedItem = dbConn.Find<T>(primaryKey);
if (storedItem != null)
{
dbConn.Update(item);
}
else if (storedItem == null)
{
dbConn.Insert(item);
primaryKey = item.PrimaryKey;
}
}

Problems with LINQ WhereClause

Many thanks to leppie:
Currently I got
Expression<Func<vwMailMerge,bool>> whereClause= null;
List<vwMailMerge> mailMergeItems = null;
int personType = mailMergeSettings.PersonType.ToInteger();
if (personType > 0)
{
whereClause = this.MailMergeWhereClause(whereClause, f => f.MemberTypeId == personType);
}
if (mailMergeSettings.PersonIds != null)
{
var personIds = mailMergeSettings.PersonIds.ToGuidArray();
if (personIds != null && personIds.Length > 0)
{
var personList = personIds.ToList();
whereClause = this.MailMergeWhereClause(whereClause, f => personList.Contains(f.UserId));
}
}
mailMergeItems = this.ObjectContext.vwMailMerges.Where(whereClause).ToList();
private Expression<Func<vwMailMerge, bool>> MailMergeWhereClause(params Expression<Func<vwMailMerge, bool>>[] wheres)
{
if (wheres.Length == 0)
{
return x => true;
}
Expression result;
if (wheres[0] == null)
{
result = wheres[1].Body;
return Expression.Lambda<Func<vwMailMerge, bool>>(result, wheres[1].Parameters);
}
else
{
result = wheres[0].Body;
for (int i = 1; i < wheres.Length; i++)
{
result = Expression.And(result, wheres[i].Body);
}
return Expression.Lambda<Func<vwMailMerge, bool>>(result, wheres[0].Parameters);
}
}
}
When it gets to "mailMergeItems =" it drops and gives error: "The parameter 'f' was not bound in the specified LINQ to Entities query expression."
I've noticed that when checking only for people, or only for membertypeId, it works properly.. but combined the 2nd gives a error on it's "f=>" I think.
You cant use Func, you need to use Expression<Func>.
The + can be done via Expression.And.
Update (not tested):
Expression<Func<vwMailMerge, bool>> whereClause = null;
...
Expression<Func<vwMailMerge, bool>> MailMergeWhereClause(
params Expression<Func<vwMailMerge, bool>>[] wheres)
{
if (wheres.Length == 0) return x => true;
Expression result = wheres[0].Body;
for (int i = 1; i < wheres.Length; i++)
{
//probaby needs a parameter fixup, exercise for reader
result = Expression.And(result, wheres[i].Body);
}
return Expression.Lambda<Func<vwMailMerge,bool>>(result, wheres[0].Parameters);
}
Update 2:
The above approach fails as I expected. It might be easy to solve on .NET 4 using the ExpressionVistor class. For .NET 3.5 (or if aforementioned is too hard) the following should work.
The approach is the append the where clauses in the IQueryable directly so you end up with:
somequery.Where(x => x.foo).Where(x => x.bar).Where(x => x.baz)
IOW, you can just add them as required, but it will require some changes to the logic/flow of the code you pasted.
You could reformat your question better with the code tool.
However it looks like you could approach the problem in this way to avoid all those func expressions floating around:
this.ObjectContext.vwMailMerges.Where(mm=>IsValidMailMerge(mm,personType)).ToList()
private bool IsValidMailMerge(YourType mailmerge, YourType2 personType)
{
if(...) // type specific criteria here
return true;
else
return false;
}

Categories