For very special circumstances, I'd like to be able to store C# code in a configuration entry and fill in an empty function with this code at runtime. For example, let's say on initial run I start out with a method such as this:
bool Evaluate(int number)
{
return false;
}
I have a configuration entry that looks like this:
<add key="EvaluateCode" value="if (number > 5) { return true; } else { return false; }"/>
After loading the EvaluateCode configuration entry I'd like to replace the function body of Evaluate so that it looks like this:
bool Evaluate(int number)
{
if (number > 5) { return true; } else { return false; }
}
After this 'replacement' is made, the Evaluate function should behave as the code dictates, just as it would as if the code had not been loaded dynamically.
How could I acheive this in C#?
Bonus: What would be the risks of implementing such a feature? How can I mitigate those risks?
Essentially you are asking for the ability to compile c# code at run time, which is possible, and is described here
This sounded like fun.. so I decided to try it.
No need to upvote.. just popping this here so I can reference it in future :)
Given the below class:
class DynamicMethodTest {
private MethodInfo _methodToCall;
private object _obj;
public void PerformInjection(string newBody) {
using (var codeProvider =
new Microsoft.CSharp.CSharpCodeProvider()) {
var res = codeProvider.CompileAssemblyFromSource(
new System.CodeDom.Compiler.CompilerParameters() {
GenerateInMemory = true
},
"public class StubClass { public bool Evaluate(int number) { " + newBody + " }}"
);
var type = res.CompiledAssembly.GetType("StubClass");
_obj = Activator.CreateInstance(type);
_methodToCall = _obj.GetType().GetMethod("Evaluate");
}
}
public bool Evaluate(int number) {
if (_methodToCall != null)
return (bool)_methodToCall.Invoke(_obj, new object[] { number });
return false;
}
}
We can do this:
public class Program {
public static void Main() {
var dynamicTest = new DynamicMethodTest();
Console.WriteLine(dynamicTest.Evaluate(15)); // False
dynamicTest.PerformInjection("if (number > 5) { return true; } else { return false; }");
Console.WriteLine(dynamicTest.Evaluate(15)); // True
Console.Read();
}
}
This results in:
False
True
As output. Basically, before the "Injection" (its not really injection.. its more of a fascade) the method returns false. After "Injection" it returns true (as expected).
Related
hey i'm making a discord bot and im trying to set it so that with a command a bool can be set to true / false (it will initiate a different response futher on) but when i do it, it stays as false despite it being set to true. im fairly sure its due to not passing the variable through. how would i go about doing it in this instance?
the bool is called (opse)
namespace ConsoleApp5
{
public class Commands : ModuleBase<SocketCommandContext>
{
bool opse;
[Command("opsset")]
public async Task trueset(string op)
{
if (op == "true")
{
opse = false;
Console.WriteLine("Operations is set to active! Set by " +
Context.Message.Author.Username);
}
if (op == "false")
{
opse = true;
Console.WriteLine("Operations is set to inactive! Set by " +
Context.Message.Author.Username);
}
}
[Command("operations")]
public async Task ops()
{
if (opse = true)
{
await Context.Channel.SendMessageAsync("Operations are not currently active. Check your
designated schedule to see when operations are active");
}
if (opse = false)
{
await Context.Channel.SendMessageAsync("Operations are currently active. Message you SO
or file an absent report");
}
}
}
}
You're using a single = to check for the value of opse, which is incorrect. A single = is used to assign new values.
To compare values you should use ==:
if (opse == true)
{
...
}
if (opse == false)
{
...
}
I am working on a unit test for a project and I cannot figure out how to get NSubstitute to work the way I would expect it to. The issue I am having is that the code I was to substitute is in a while loop and depending on what is returned from the substituted value determines if the loop continues.
What I would like to do is have Process() return a different result based on what is passed in. I have tried
api.Process(Arg.Is<IEnumerable<int>>(new[] {1,2,3}, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
but it does not seems to work as processingResult comes back null because NSubstitue is not matching the argument.
[Test]
public void TestTwoLoops()
{
var api = Substitute.For<IApi>();
api.Process(/*list containing 1,2,3*/, Arg.Any<bool>()).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
api.Process(/*list containing 30*/, Arg.Any<bool>()).Returns(new List<int>{});
var sut = new WidgetMaker(api);
sut.MakeWidget();
}
public class WidgetMaker
{
public WidgetMaker(IApi api)
{
_api = api;
}
public void MakeWidgets(IEnumerable<int> widgetIds)
{
var idsToProcess = widgetIds.ToList();
while(true)
{
if(!idsToProcess.Any())
{
berak;
}
var processingResult = _api.Process(idsToProcess, false);
if(processingResult.Success)
{
idsToProcess.Clear();
idsToProcess.AddRange(processingResult.IdsNotProcessed);
}
else
{
break;
}
}
}
private IApi _api;
}
As I was writing this question, the answer came to me, but I have a feeling others might find this helpful.
Using the overload that accepts a predicate and using the SequenceEqualExtension method with a parameter of new[] {/values I want to be input/}
api.Process(Arg.Is<IEnumerable<int>>(x => x.SequenceEqual(new[] {1,2,3}, Arg.Any<bool>())).Returns(new ProcessingResult(){Success = true, IdsNotProcessed = List<int>{30}});
I have a bit of logic in my code and I'm wondering if there's a better way of re-writing it. I have two user-defined server objects (serverA and serverB) and I want to proceed if both of them are of enum ServerType Web or Database.
Current code is clumsy:
if((serverA.ServerType == ServerType.Web || serverA.ServerType == ServerType.Database) && (serverB.ServerType == ServerType.Web || serverB.ServerType == ServerType.Database))
{
// do stuff
}
I'm after an elegant succinct way of writing that.
I would have a new property in your user-defined server object
public class Server
{
public ServerType ServerType { get; set; }
public bool IsDatabaseOrWeb
{
get
{
return ServerType == ServerType.Web || ServerType == ServerType.Database;
}
}
}
then your function would look like this
if (serverA.IsDatabaseOrWeb && serverB.IsDatabaseOrWeb)
{
// do stuff
}
This way spells out more clearly that you are asking the same question about both servers and allows you to change the condition in one place if needed.
if(IsRightType(serverA) && IsRightType(serverB))
{
// do stuff
}
bool IsRightType(Server server)
{
return server.ServerType == ServerType.Web || server.ServerType == ServerType.Database;
}
Maybe following solution would be more elegant. Implement an abstract class so all your server objects would inherit from it.
public enum ServerType
{
Web,
Database,
SomethingElse
}
public class ServerA : ServerObject
{
}
public class ServerB : ServerObject
{
}
public abstract class ServerObject
{
public ServerType ServerType { get; set; }
}
And then implement a method for checking if an object meets your condition.
public bool IfWebOrDatabase(ServerObject so)
{
return so.ServerType == ServerType.Web || so.ServerType == ServerType.Database;
}
And use a much shorter version of the If then.
if (IfWebOrDatabase(serverA) && IfWebOrDatabase(serverB))
{
// do stuff
}
A similar approach is to use extension method for enum ServerType. A possible way to write the code would be the following:
public enum ServerType
{
Web,
Database,
Bi
}
public static class Extensions
{
public static bool IsOperational(this ServerType st)
{
var operationalTypes = new List<ServerType> { ServerType.Web, ServerType.Database };
return operationalTypes.Contains(st);
}
}
class Program
{
static void Main(string[] args)
{
var st1 = ServerType.Web;
var st2 = ServerType.Database;
var st3 = ServerType.Bi;
bool isSt1Operational = st1.IsOperational();
bool isSt2Operational = st2.IsOperational();
bool isSt3Operational = st3.IsOperational();
}
}
Add a property to the class that contains ServerType:
public bool IsDatabaseOrWeb
{
get
{
return (ServerType == ServerType.Web || ServerType == ServerType.Database);
}
}
Then use it like:
if(ServerA.IsDatabaseOrWeb && ServerB.IsDatabaseOrWeb)
{
}
The trend you should be noticing in these answers is that the solution is worse than the problem. If you wanted to use lambda expressions in linq, it gets even worse:
if (new Server[] { serverA, serverB }.All(s => new ServerType[] { ServerType.Web, ServerType.Database }.Contains(s.ServerType)))
{
}
Even if you break it apart:
var badIdea = new Server[] { entity, serverB };
var alsoBad = new ServerType[] { ServerType.Web, ServerType.Database };
if (badIdea.All(s => alsoBad.Contains(s.ServerType)))
{
}
Sometimes the simplest expression is still messy. Your if statement is fine unchanged. Maybe just put a carriage return in the middle so that you can see it on the screen all at once.
Bitflags may help here.
[Flags]
public enum ServerType
{
None = 0,
Web=1,
Database = 2,
Other = 4
}
To use it
var flags = ServerType.Web | ServerType.Database;
var bothWebOrDb = (serverA.ServerType & flags)
& (serverB.ServerType & flags);
if (bothWebOrDb != ServerType.None)
{
}
Which be reduced to the following
var flags = ServerType.Web | ServerType.Database;
var bothWebOrDb = serverA.ServerType & serverB.ServerType & flags;
if (bothWebOrDb != ServerType.None)
{
}
This problem is affecting my ASP.Net WebApi Patch method which looks a lot like this:
public MyModel Patch(int id, [FromBody]Delta<MyModel> newRecord){/*stuff here*/}
But it's not WebApi that's the problem - the failure is between Json.Net and OData.Delta.
The problem is JsonConvert.DeserializeObject does not see integers of OData.Delta objects and I'm wondering if there's a workaround or fix I can apply.
UPDATE: Have written code (see right down below) in the Json.Net library that will fix this. Just need it to be included in the next update (if James Newton-King allows it)
UPDATE 2: After further testing, I've decided the best course of action is to stop using OData.Delta and write my own (see answer)
Unit tests to prove the problem exists (using statements moved below for clarity)
Test 1: Fails with an int (Int32):
class TestObjWithInt
{
public int Int { get; set; }
}
[TestMethod]
public void IsApplied_When_IntIsDeserializedToDelta()
{
string testData = "{\"Int\":1}";
var deserializedDelta = JsonConvert.DeserializeObject<Delta<TestObjWithInt>>(testData);
var result = deserializedDelta.GetChangedPropertyNames().Contains("Int");
Assert.IsTrue(result);
}
Test 2: Succeeds with a long (Int64)
class TestObjWithLong
{
public long Long { get; set; }
}
[TestMethod]
public void IsApplied_When_LongIsDeserializedToDelta()
{
string testData = "{\"Long\":1}";
var deserializedDelta = JsonConvert.DeserializeObject<Delta<TestObjWithLong>>(testData);
var result = deserializedDelta.GetChangedPropertyNames().Contains("Long");
Assert.IsTrue(result);
}
And just to be sure that deserialization works to begin with, these two tests both pass.
[TestMethod]
public void IsApplied_When_LongIsDeserializedToTestObject()
{
string testData = "{\"Long\":1}";
var deserializedObject = JsonConvert.DeserializeObject<TestObjWithLong>(testData);
var result = deserializedObject.Long == 1;
Assert.IsTrue(result);
}
[TestMethod]
public void IsApplied_When_IntIsDeserializedToTestObject()
{
string testData = "{\"Int\":1}";
var deserializedObject = JsonConvert.DeserializeObject<TestObjWithInt>(testData);
var result = deserializedObject.Int == 1;
Assert.IsTrue(result);
}
I found this OData bug report which sounds like a similar issue but its old and closed so probably not.
Any help would be great.
Using statements (from the top of the test file):
using System;
using System.Linq;
using System.Web.Http.OData;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Newtonsoft.Json;
Solution if accepted by James Newton-King - change to release 6.0.6.
Replace JsonSerializerInternalReader.cs line 1581:
contract.TrySetMember(newObject, memberName, value);
with:
bool done = false;
while (!(done = done || contract.TrySetMember(newObject, memberName, value)))
{
switch (reader.TokenType)
{
case JsonToken.Integer:
if (value is long && ((long)value) <= Int32.MaxValue && ((long)value) >= Int32.MinValue)
value = Convert.ToInt32(value);
//Add else if (...) to cast to other data types here (none additional required to date).
else
done = true;
break;
default:
done = true;
break;
}
}
OData.Delta<T> does not work with Json.Net for any number Types other than Int64. The easiest approach is to write a replacement for OData.Delta<T> (which I've done on company time so I can't post it in its entirety sorry) containing methods like this:
private bool TrySetInt32(object value, PropertyInfo propertyInfo, bool isNullable)
{
var done = false;
if (value is Int32)
{
propertyInfo.SetValue(_obj, value);
done = true;
}
else if (value == null)
{
if (isNullable)
{
propertyInfo.SetValue(_obj, value);
done = true;
}
}
else if (value is Int64) //Json.Net - fallback for numbers is an Int64
{
var val = (Int64)value;
if (val <= Int32.MaxValue && val >= Int32.MinValue)
{
done = true;
propertyInfo.SetValue(_obj, Convert.ToInt32(val));
}
}
else
{
Int32 val;
done = Int32.TryParse(value.ToString(), out val);
if (done)
propertyInfo.SetValue(_obj, val);
}
return done;
}
The class can be a dynamic generic like this:
public sealed class Patchable<T> : DynamicObject where T : class, new()
With a working variable like this:
T _obj = new T();
In the overridden TrySetMember method, we need to check the underlying type of the property using reflection and call the appropriate TrySet... method like this:
if (underlyingType == typeof(Int16))
done = TrySetInt16(value, propertyInfo, isNullable);
else if (underlyingType == typeof(Int32))
done = TrySetInt32(value, propertyInfo, isNullable);
If the value is set successfully we can add the property name to a list that we can then use for patching the original record like this:
if (done)
_changedPropertyNames.Add(propertyInfo.Name);
public void Patch(T objectToPatch)
{
foreach (var propertyName in _changedPropertyNames)
{
var propertyInfo = _obj.GetType().GetProperty(propertyName);
propertyInfo.SetValue(objectToPatch, propertyInfo.GetValue(_obj));
}
}
68 unit tests later, it all seems to work pretty well. Here's an example:
class TestObjWithInt32
{
public Int32 Int32 { get; set; }
public Int32? SetNullable { get; set; }
public Int32? UnsetNullable { get; set; }
}
[TestMethod]
public void IsApplied_When_Int32IsDeserializedToPatchable()
{
string testData = "{\"Int32\":1,\"SetNullable\":1}";
var deserializedPatchable = JsonConvert.DeserializeObject<Patchable<TestObjWithInt32>>(testData);
var result = deserializedPatchable.ChangedPropertyNames.Contains("Int32");
Assert.IsTrue(result);
var patchedObject = new TestObjWithInt32();
Assert.AreEqual<Int32>(0, patchedObject.Int32);
deserializedPatchable.Patch(patchedObject);
Assert.AreEqual<Int32>(1, patchedObject.Int32);
Assert.IsNull(patchedObject.UnsetNullable);
Assert.IsNotNull(patchedObject.SetNullable);
}
This is my implementation for this issue based on Rob solution:
public sealed class Patchable<T> : DynamicObject where T : class {
private readonly IDictionary<PropertyInfo, object> changedProperties = new Dictionary<PropertyInfo, object>();
public override bool TrySetMember(SetMemberBinder binder, object value) {
var pro = typeof (T).GetProperty(binder.Name);
if (pro != null)
changedProperties.Add(pro, value);
return base.TrySetMember(binder, value);
}
public void Patch(T delta) {
foreach (var t in changedProperties)
t.Key.SetValue(
delta,
t.Key.PropertyType.IsEnum ? Enum.Parse(t.Key.PropertyType, t.Value.ToString()) : Convert.ChangeType(t.Value, t.Key.PropertyType));
}
}
I removed the requisite of an empty constructor in generic type parameter using the dictionary instead of a temporal object.
Thanks Rob ;)
I am writing a bunch of integration tests for a project. I want to call each individual integration point method wrapped in a try/catch block so that when it fails, I get some sort of feedback to display, rather than just crashing the app. I also want to be able to time how long the calls take, and check return values when needed. So, I have an IntegrationResult class with some basic description, result and time elapsed properties:
class IntegrationResult
{
private StopWatch _watch;
public string Description {get;set;}
public string ResultMessage {get;set;}
public bool TestPassed {get;set;}
public string TimeElapsed {get { return _watch == null ? "0" : _watch.Elapsed.TotalMilliseconds.ToString(); } }
public void Start()
{
_watch = StopWatch.StartNew();
}
public void Stop()
{
_watch.Stop();
}
}
The code I keep writing looks like this:
IntegrationResult result = new IntegrationResult();
result.Description = "T-SQL returns expected results";
try
{
result.Start();
SomeIntegrationPoint("potential arguments"); //This is the line being tested
result.Stop();
//do some check that correct data is present
result.TestPassed = true;
result.ResultMessage = "Pulled 10 correct rows";
}
catch(Exception e)
{
result.TestPassed = false;
result.ResultMessage = String.Format("Error: {0}", e.Message);
}
I would really like to be able to just pass the SomeIntegrationPoint method in as an argument and a delegate or something to check the results, but I can't figure out if that's even possible. Are there any frameworks to handle this type of testing, or do you have any suggestions on how I might simplify the code for better reuse? I'm tired of typing this block ;)
(I'm assuming this is C#, as tagged... though the syntax was not in the question.)
You can do this. Just change your result class to include:
class IntegrationResult
{
string Description { get; set; }
string SuccessResultMessage { get; set; }
string FailResultMessage { get; set; }
public IntegrationResult(string desc, string success, string fail)
{
this.Description = desc;
this.SuccessResultMessage = success;
this.FailResultMessage = fail;
}
public bool ExecuteTest(Func<IntegrationResult, bool> test)
{
bool success = true;
try
{
this.Start();
success = test(this);
this.Stop();
this.ResultMessage = success ?
this.SuccessResultMessage :
this.FailResultMessage;
this.TestPassed = true;
}
catch(Exception e)
{
this.TestPassed = false;
this.ResultMessage = String.Format("Error: {0}", e.Message);
success = false;
}
return success;
}
...
You could then change your code for your tests to:
private void myDoTestMethod(string argumentOne, string argumentTwo)
{
IntegrationResult result = new IntegrationResult(
"T-SQL returns expected results",
"Pulled 10 correct rows",
"Wrong number of rows received");
result.Execute( r=>
{
integrationPoint.call(argumentOne, argumentTwo);
//do some check that correct data is present (return false if not)
return true;
});
}
This can easily be extended to include your timings as well.
Have you looked into AOP? PostSharp looks like a nice place to start. There is also an example on exception handling aspects.