I'm using Ncalc in my new project and it already has almost everything I need .
I said almost everything, because now I need to expand some functions and also add new ones such as : nth root,random, etc
Do you know if anyone has already implemented those functions? Or could you give me any tips or guides to extend the function list of Ncalc???
Thanks in advance.
If I understand correctly:
As much as I was using it is by creating a static function
private static void NCalcExtensionFunctions(string name, FunctionArgs functionArgs)
{
if (name == "yourfunctionname")
{
var param1 = functionArgs.Parameters[0].Evaluate();
var param2 = functionArgs.Parameters[1].Evaluate();
//... as many params as you require
functionArgs.Result = (int)param1 * (int)param2; //do your own function logic here
}
if (name == "random")
{
if(functionArgs.Parameters.Count() == 0)
{
functionArgs.Result = new Random().Next();
}
else if(functionArgs.Parameters.Count() == 1)
{
functionArgs.Result = new Random().Next((int)functionArgs.Parameters[0].Evaluate());
}
else
{
functionArgs.Result = new Random().Next((int)functionArgs.Parameters[0].Evaluate(), (int)functionArgs.Parameters[1].Evaluate());
}
}
}
And then you use it as follows
var expr = new Expression("yourfunctionname(3, 2)");
expr.EvaluateFunction += NCalcExtensionFunctions;
var result = expr.Evaluate();
var randExpr = new Expression("random(100)");
randExpr.EvaluateFunction += NCalcExtensionFunctions;
var resultRand = randExpr.Evaluate();
I hope I didn't mistype any of the code. A list of NCalc built-in functions can be found here: http://ncalc.codeplex.com/wikipage?title=functions&referringTitle=Home
Related
I'm working with TwincatAds.Reactive 6.0.190 in .NET 6 WPF Desktop application.
I'm also using MVVM pattern.
My goal is to create a Class that is going to observe for a PLC Variable changes, collect those variables to a dictionary, and later on use those values in the ViewModel.
Here's the method where I'm attaching the notification and action where I'm handling the notification.
public void AttachNotification(IEnumerable<(string key, Type type)> Symbols)
{
_observerValueNotification = Observer.Create<ValueNotification>(val =>
{
// Does handle really start from 2?
var handle = val.Handle;
if (val.UserData is object[] objects)
{
string tag = objects[handle - 2].ToString();
if (!_values.Any(x => x.Key == tag))
_values.Add(new SymbolModel { Key = tag, Value = val.Value });
else
{
var symbol = _values.First(x => x.Key == tag);
symbol.Value = val.Value;
}
}
ValuesChanged?.Invoke(_values);
});
if (_plcWrapper.AdsClient != null)
{
// Get Symbols from SymbolLoader
List<AnySymbolSpecifier> list = new();
List<string> userData = new();
foreach (var (key, type) in Symbols)
{
list.Add(new AnySymbolSpecifier(key, new AnyTypeSpecifier(type)));
userData.Add(key);
}
_subscription2 = _plcWrapper.AdsClient.WhenNotificationEx(list, NotificationSettings.ImmediatelyOnChange, userData.ToArray())
.Subscribe(_observerValueNotification);
}
}
I'm using ValueNotification simply because, I'd like to use this pattern also for complex PLC Variables like Structs.
As You can see, in the WhenNotificationEx method I'm using UserData[] to provide some sort of identification of what Variable has changed when handling the change.
My idea was to use Handle property from ValueNotification as an indexer in UserData[] to identify what variable I'm dealing with, but for some reason Handle starts from 2.
My question is, is it expected behaviour, does the Handle value really always start from 2?
I've decided that relying on the Handle being index in the UserData array is quite unpredictable as Handle is being created by the Twincat Ads server.
Solved the issue by creating own extension method to the WhenNotificationEx. Turned out IDisposableHandleBag has exactly what I was looking for, which is SourceResultHandles property, where AnySymbolSpecifier and ResultHandle are both stored!
Here's created extension method
public static Dictionary<string, uint> Handles { get; private set; } = new();
public static IObservable<ValueNotification> WhenNotificationWithHandle(this IAdsConnection connection, IList<AnySymbolSpecifier> symbols, NotificationSettings settings)
{
IAdsConnection connection2 = connection;
IList<AnySymbolSpecifier> symbols2 = symbols;
NotificationSettings settings2 = settings;
if (connection2 == null)
{
throw new ArgumentNullException("connection");
}
if (symbols2 == null)
{
throw new ArgumentNullException("symbols");
}
if (symbols2.Count == 0)
{
throw new ArgumentOutOfRangeException("symbols", "Symbol list is empty!");
}
IDisposableHandleBag<AnySymbolSpecifier> bag = null;
EventLoopScheduler scheduler = new EventLoopScheduler();
IObservable<int> whenSymbolChangeObserver = connection2.WhenSymbolVersionChanges(scheduler);
IDisposable whenSymbolChanges = null;
Action<EventHandler<AdsNotificationExEventArgs>> addHandler = delegate (EventHandler<AdsNotificationExEventArgs> h)
{
connection2.AdsNotificationEx += h;
bag = ((IAdsHandleCacheProvider)connection2).CreateNotificationExHandleBag(symbols2, relaxSubErrors: false, settings2, null);
bag.CreateHandles();
// Collect Handles
Handles.Clear();
foreach (var item in bag.SourceResultHandles)
Handles.Add(item.source.InstancePath, item.result.Handle);
whenSymbolChanges = whenSymbolChangeObserver.Subscribe((Action<int>)delegate
{
bag.CreateHandles();
Handles.Clear();
foreach (var item in bag.SourceResultHandles)
Handles.Add(item.source.InstancePath, item.result.Handle);
}, (Action<Exception>)delegate
{
TcTraceSource traceAds = AdsModule.TraceAds;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(101, 1);
defaultInterpolatedStringHandler.AppendLiteral("The AdsServer '");
defaultInterpolatedStringHandler.AppendFormatted(connection2.Address);
defaultInterpolatedStringHandler.AppendLiteral("' doesn't support SymbolVersionChanged Notifications! Handle recreation is not active!");
traceAds.TraceInformation(defaultInterpolatedStringHandler.ToStringAndClear());
});
};
Action<EventHandler<AdsNotificationExEventArgs>> removeHandler = delegate (EventHandler<AdsNotificationExEventArgs> h)
{
if (whenSymbolChanges != null)
{
whenSymbolChanges.Dispose();
}
scheduler.Dispose();
if (bag != null)
{
bag.Dispose();
bag = null;
Handles.Clear();
}
connection2.AdsNotificationEx -= h;
};
return from ev in Observable.FromEventPattern<EventHandler<AdsNotificationExEventArgs>, AdsNotificationExEventArgs>(addHandler, removeHandler)
where bag.Contains(ev.EventArgs.Handle)
select new ValueNotification(ev.EventArgs, ev.EventArgs.Value);
}
My use case - I want to render the same template using different model instances from a Powershell script. I wrap Razorlight in an exe tool, but I do not want to call the tool with all the model objects at once - instead I want to be able to pass them as they become available.
This means I cannot use the MemoryCachingProvider. What I need is a file system caching provider and a way to reuse it between the calls to the tool.
Is there anything off-the-shelf?
EDIT 1
So I am banging the wall this whole day on this thing. I have the generated Assembly object, but it is not serializable. It is an in-memory assembly, so no file on disk. And there seems to be no way in RazorLight to instruct the compilation to save it on disk.
I must be missing something really obvious here, at least this is the sentiment I get from the first comment to this post. Please, put me out of my misery - share what am I missing here.
So I failed to find a way to do it in the current version of RazorLight. I am extremely curious as to the "too many ways to approach this problem".
Anyway, my solution to the problem is to modify the RazorLight code to enable such a feature. Here is the PR - https://github.com/toddams/RazorLight/pull/492
If merged and released, then it would be possible to write a cache like this:
public class FileSystemCachingProvider : ICachingProvider
{
private MemoryCachingProvider m_cache = new();
private readonly string m_root;
public FileSystemCachingProvider(string root)
{
m_root = root;
}
public void PrecreateAssemblyCallback(IGeneratedRazorTemplate generatedRazorTemplate, byte[] rawAssembly, byte[] rawSymbolStore)
{
var srcFilePath = Path.Combine(m_root, generatedRazorTemplate.TemplateKey[1..]);
var asmFilePath = srcFilePath + ".dll";
File.WriteAllBytes(asmFilePath, rawAssembly);
if (rawSymbolStore != null)
{
var pdbFilePath = srcFilePath + ".pdb";
File.WriteAllBytes(pdbFilePath, rawSymbolStore);
}
}
public void CacheTemplate(string key, Func<ITemplatePage> pageFactory, IChangeToken expirationToken)
{
}
public bool Contains(string key)
{
var srcFilePath = Path.Combine(m_root, key);
var asmFilePath = srcFilePath + ".dll";
if (File.Exists(asmFilePath))
{
var srcLastWriteTime = new FileInfo(srcFilePath).LastWriteTimeUtc;
var asmLastWriteTime = new FileInfo(asmFilePath).LastWriteTimeUtc;
return srcLastWriteTime < asmLastWriteTime;
}
return false;
}
public void Remove(string key)
{
var srcFilePath = Path.Combine(m_root, key);
var asmFilePath = srcFilePath + ".dll";
var pdbFilePath = srcFilePath + ".pdb";
if (File.Exists(asmFilePath))
{
File.Delete(asmFilePath);
}
if (File.Exists(pdbFilePath))
{
File.Delete(pdbFilePath);
}
}
public TemplateCacheLookupResult RetrieveTemplate(string key)
{
var srcFilePath = Path.Combine(m_root, key);
var asmFilePath = srcFilePath + ".dll";
if (File.Exists(asmFilePath))
{
var srcLastWriteTime = new FileInfo(srcFilePath).LastWriteTimeUtc;
var asmLastWriteTime = new FileInfo(asmFilePath).LastWriteTimeUtc;
if (srcLastWriteTime < asmLastWriteTime)
{
var res = m_cache.RetrieveTemplate(key);
if (res.Success)
{
return res;
}
var rawAssembly = File.ReadAllBytes(asmFilePath);
var pdbFilePath = srcFilePath + ".pdb";
var rawSymbolStore = File.Exists(pdbFilePath) ? File.ReadAllBytes(pdbFilePath) : null;
return new TemplateCacheLookupResult(new TemplateCacheItem(key, CreateTemplatePage));
ITemplatePage CreateTemplatePage()
{
var templatePageTypes = Assembly
.Load(rawAssembly, rawSymbolStore)
.GetTypes()
.Where(t => typeof(ITemplatePage).IsAssignableFrom(t) && !t.IsAbstract && !t.IsInterface)
.ToList();
if (templatePageTypes.Count != 1)
{
throw new ApplicationException($"Code bug: found {templatePageTypes.Count} concrete types implementing {nameof(ITemplatePage)} in the generated assembly.");
}
m_cache.CacheTemplate(key, CreateTemplatePage);
return CreateTemplatePage();
ITemplatePage CreateTemplatePage() => (ITemplatePage)Activator.CreateInstance(templatePageTypes[0]);
}
}
}
return new TemplateCacheLookupResult();
}
}
And then one could use it like this:
string root = Path.GetDirectoryName(m_razorTemplateFilePath);
var provider = new FileSystemCachingProvider(root);
var engine = new RazorLightEngineBuilder()
.UseFileSystemProject(root, "")
.UseCachingProvider(provider)
.AddPrecreateAssemblyCallbacks(provider.PrecreateAssemblyCallback)
.Build();
I hope someone can help with this. For a few years now, I've been iterating through my searchresult using a LOT of If statements to populate all of the properties in my class. There are over 300 properties that I need to populate.. but that is an awful lot of if statements. As an example, this is what I mean:
var myCon = StarfishLDAPCon.CreateDirectoryEntry(objectContainer, whichCM);
var ds = new DirectorySearcher(myCon);
ds.Filter = "(deftyAgentID=07629)";
var result = ds.FindOne();
AgentID returnValue = new AgentID();
if (result.Properties.Contains("deftyAgentID"))
{
returnValue.DeftyAgentID = result.Properties["deftyAgentID"][0].ToString();
}
if (result.Properties.Contains("deftySecuritycode"))
{
returnValue.DeftyAgentID = result.Properties["deftySecuritycode"][0].ToString();
}
if (result.Properties.Contains("deftyAgentACWAgentConsdrdIdle"))
{
returnValue.DeftyAgentACWAgentConsdrdIdle = result.Properties["deftyAgentACWAgentConsdrdIdle"][0].ToString();
}
I have over 300 of those if statements. I'm hoping there's some cool way to do this without all those if statements? Anyone have any ideas?
Thanks for any help!
Dave M.
Well pretty simple - just write a small extension method like this:
public static class SearchResultExtension
{
public string GetPropertyValue(this SearchResult result, string propName)
{
if (result == null || result.Properties == null)
{
return null;
}
if (result.Properties.Contains(propName))
{
return result.Properties[propName][0].ToString();
}
return null;
}
}
Now you can handle the 80% "normal" cases like this:
SearchResult result = ds.FindOne();
AgentID returnValue = new AgentID();
returnValue.DeftyAgentID = result.GetPropertyValue("deftyAgentID");
returnValue.DeftySecurityCode = result.GetPropertyValue("deftySecuritycode");
returnValue.DeftyAgentACWAgentConsdrdIdle = result.GetPropertyValue("deftyAgentACWAgentConsdrdIdle");
and so forth. Any cases that should not return the first element of the Properties collection as a string need to be handled separately, obviously
I'm not a developer so maybe the answer is out there for a different solution but I can't really translate it from python or something else.
I'm trying to use the AWS .NET SDK to find an instance and then get the instance's tags. I've gotten as far as being able to determine if an instance is up and running or not. I also see how I can create and delete tags (not in code example below). But I don't see an easy way to actually check if a tag exists and get the value of the tag if it does exist.
Sorry if I'm missing the obvious but this is all new to me. Here's an example of the code I'm using to check if an instance is running.
instanceID = "i-myInstanceID";
do {
var myrequest = new DescribeInstanceStatusRequest();
DescribeInstanceStatusResponse myresponse = ec2.DescribeInstanceStatus(myrequest);
int isCount = myresponse.DescribeInstanceStatusResult.InstanceStatuses.Count;
for (int isc=0; isc < isCount; isc++) {
InstanceStatus instanceStatus = myresponse.DescribeInstanceStatusResult.InstanceStatuses[isc];
if (instanceStatus.InstanceId.Contains(instanceID)) {
Console.WriteLine("It looks like instance "+instanceID+" is running.");
idIdx = isc;
foundID = true;
break;
}
}
if ((foundID==false) && (secondCounter==1)) {
Console.Write("Looking for instance "+instanceID);
} else {
Console.Write(".");
}
Thread.Sleep(1000);
secondCounter++;
if (secondCounter > 5) {
break;
}
} while (foundID == false) ;
First send a DescribeInstancesRequest to get the list of Instances:
public DescribeInstancesResult GetInstances(Ec2Key ec2Key)
{
_logger.Debug("GetInstances Start.");
AmazonEC2 ec2 = CreateAmazonEc2Client(ec2Key);
var ec2Request = new DescribeInstancesRequest();
DescribeInstancesResponse describeInstancesResponse = ec2.DescribeInstances(ec2Request);
DescribeInstancesResult result = describeInstancesResponse.DescribeInstancesResult;
_logger.Debug("GetInstances End.");
return result;
}
Then loop through the instances until you find the one you want, and then use the Tag.GetTagValueByKey method:
// This just calls the above code
DescribeInstancesResult ec2Instances = _ec2ResourceAccess.GetInstances(ec2Key);
var returnInstances = new List<Ec2UtilityInstance>();
foreach (var reservation in ec2Instances.Reservation)
{
foreach (var runningInstance in reservation.RunningInstance)
{
var returnInstance = new Ec2UtilityInstance();
returnInstance.InstanceId = runningInstance.InstanceId;
returnInstance.InstanceName = runningInstance.Tag.GetTagValueByKey("Name");
returnInstance.Status = (Ec2UtilityInstanceStatus)Enum.Parse(typeof(Ec2UtilityInstanceStatus), runningInstance.InstanceState.Name, true);
returnInstance.DefaultIp = runningInstance.Tag.GetTagValueByKey("DefaultIp");
returnInstance.InstanceType = runningInstance.InstanceType;
returnInstance.ImageId = runningInstance.ImageId;
returnInstances.Add(returnInstance);
}
}
Here is the link for full source that this was taken from:
https://github.com/escherrer/EC2Utilities
Common\Manager
and
Common\ResourceAccess
I have my code and I would like to optimize it. For me it looks like it's already optimized. Can anyone suggest how I could make it a bit more optimized?
if (target == "power")
{
return new JsonResult { Data = new { RC = new Data.AdminPower(datastoreValue).Refresh() } };
}
if (target == "notes")
{
return new JsonResult { Data = new { RC = new Data.AdminNotes(datastoreValue).Refresh() } };
}
if (target == "book")
{
return new JsonResult { Data = new { RC = new Data.AdminBook(datastoreValue).Refresh() } };
}
return null;
switch statements are great for these situations:
switch(target)
{
case "power":
return new JsonResult { Data = new { RC = new Data.AdminPower(datastoreValue).Refresh() } };
case "notes":
return new JsonResult { Data = new { RC = new Data.AdminNotes(datastoreValue).Refresh() } };
case "book":
return new JsonResult { Data = new { RC = new Data.AdminBook(datastoreValue).Refresh() } };
default:
return null;
}
Dont really need the breaks tho, since it will be returning each time, but its good practice..
If you know that your method will be called more often with "book" values, then you should put that first. Basically sort by order of frequency.
As someone else mentioned, you should put them in order of most likely to occur to minimize your total number of incorrect comparisons.
Maybe it's possible to change "power" "notes" and "book" to an enum or int representation, and that may be slightly faster than the string comparisons.
There's not a whole lot you can do that will result in any significant optimizations, though.
I don't know what's your idea about optimized,
as a matter of speed, just put some 'else' before second and third 'if's
but if you mean less code lines, then may be something like this could help you:
return
((target == "power") ? new JsonResult { Data = new { RC = new Data.AdminPower(datastoreValue).Refresh() } } :
((target == "notes") ? new JsonResult { Data = new { RC = new Data.AdminNotes(datastoreValue).Refresh() } } :
((target == "book") ? new JsonResult { Data = new { RC = new Data.AdminBook(datastoreValue).Refresh() } } : null))))
The only thing I would do is change the ifs to an if-elseif chain. There isn't really anything else you can do to improve performance.