In the following code using JINT, the call to the Setup1 method works and the call to Setup2 method does not. The call to Setup2 raises the error: Jint.Runtime.JavaScriptException: 'No public methods with the specified arguments were found.'
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApp4
{
public delegate bool DoFunction();
public class TestClass
{
public TestClass() { }
public void Setup1(Func<bool> fn)
{
bool b = fn();
}
public void Setup2(DoFunction fn)
{
bool b = fn();
}
}
class Program
{
static void Main(string[] args)
{
Jint.Engine _engine = new Jint.Engine();
_engine.SetValue("test", new TestClass());
_engine.Execute("test.Setup1(function() { return true; })");
_engine.Execute("test.Setup2(function() { return true; })");
}
}
}
So why does the call to Setup2 fail? What is the different between Func and the delegate DoFunction()?
Related
I'm getting an error that I don't understand. The simplified version of my code:
using UnityEngine;
public class RunLater : MonoBehaviour
{
public static void Do()
{
Invoke("RunThisLater", 2.0f);
}
public void RunThisLater()
{
Debug.Log("This will run later");
}
}
You can pass it in as a parameter like this:
public class RunLater : MonoBehaviour
{
public static void Do(RunLater instance)
{
instance.Invoke("RunThisLater", 2.0f);
}
public void RunThisLater()
{
Debug.Log("This will run later");
}
}
One approach is to have the static parts of the class store a MonoBehaviour reference to itself. Like so:
public class RunLater : MonoBehaviour
{
public static RunLater selfReference = null;
public static void Do()
{
InitSelfReference();
selfReference.DoInstanced();
}
static void InitSelfReference()
{
if (selfReference == null)
{
// We're presuming you only have RunLater once in the entire hierarchy.
selfReference = Object.FindObjectOfType<RunLater>();
}
}
public void DoInstanced()
{
Invoke("RunThisLater", 2f);
}
void RunThisLater()
{
Debug.Log("This will run later");
}
}
You would now be able to call RunLater.Do() from anywhere in your code of other gameObjects. Good luck!
I'm trying to create a convenient serialized reference to asset objects. It serialized correctly, but deserialization fails with exception
"Error setting value to 'textAssetRef' on 'TestData'."
I've prepared a small test component for Unity to illustrate this:
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using UnityEditor;
using UnityEngine;
public class Test : MonoBehaviour
{
public TestData testData;
public void Awake()
{
try
{
var sData = JsonConvert.SerializeObject(testData, Formatting.Indented);
UnityEngine.Debug.Log(sData);
testData = JsonConvert.DeserializeObject<TestData>(sData);
UnityEngine.Debug.Log("Done.");
}
catch (Exception x)
{
UnityEngine.Debug.LogError(x.Message);
}
}
}
[Serializable]
public class TestData
{
public TextAssetRef textAssetRef;
}
[Serializable]
[JsonConverter(typeof(Serialization))]
public class TextAssetRef : ObjectRef<TextAsset>
{
public TextAssetRef() { }
public TextAssetRef(TextAssetRef other) : base(other) { }
public TextAssetRef(TextAsset ta) : base(ta) { }
}
[Serializable]
public class ObjectRef<T> where T : UnityEngine.Object
{
public T obj;
public ObjectRef() { }
public ObjectRef(ObjectRef<T> other) { obj = other.obj; }
public ObjectRef(T obj) { this.obj = obj; }
public class Serialization : JsonConverter
{
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objRef = (ObjectRef<T>)value;
var jObject = new JObject { { "path", AssetDatabase.GetAssetPath(objRef.obj) } };
serializer.Serialize(writer, jObject);
}
public override bool CanConvert(Type objectType) { return objectType == typeof(ObjectRef<T>); }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
var jObject = JObject.Load(reader);
var assetPath = jObject.GetValue("path").Value<string>();
return new ObjectRef<T> { obj = AssetDatabase.LoadAssetAtPath<T>(assetPath) };
}
}
}
To reproduce the error just create a new project with JSON.Net asset package in Unity, create empty object in scene, put this Test component on it and press Play.
What am I to do to get it deserialized correctly?
Lets say I have a simple repository class, with one GetByNames method
public class MyRepo
{
private readonly MyDbContext _db;
public MyRepo(MyDbContext db)
{
_db = db;
}
public IQueryable<MyObject> GetByNames(IList<string> names)
{
if (names== null || !names.Any())
{
return Enumerable.Empty<MyObject>().AsQueryable();
}
return _db.MyObjects.Where(a => names.Contains(a.Name));
}
}
Now when I use it with async EntityFramework ToListAsync() extension
var myObjects = awawit new MyRepo(_db).GetByNames(names).ToListAsync();
It will blow up if I pass in empty list or null because Enumerable.Empty<MyObject>().AsQueryable() does not implement IDbAsyncEnumerable<MyObject> interface.
The source IQueryable doesn't implement IDbAsyncEnumerable. Only sources that implement IDbAsyncEnumerable can be used for Entity Framework asynchronous operations. For more details see http://go.microsoft.com/fwlink/?LinkId=287068.
So my question is, how can I return an empty IQueryable<> that implements IDbAsyncEnumerable, without hitting the database?
I ended up implementing an extension method that returns wrapper which implements IDbAsyncEnumerable. It is based on this boilerplate implementation for mocking async code.
With this extension method I can use
return Enumerable.Empty<MyObject>().AsAsyncQueryable();
which works great.
Implementation:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
namespace MyProject.MyDatabase.Extensions
{
public static class EnumerableExtensions
{
public static IQueryable<T> AsAsyncQueryable<T>(this IEnumerable<T> source)
{
return new AsyncQueryableWrapper<T>(source);
}
public static IQueryable<T> AsAsyncQueryable<T>(this IQueryable<T> source)
{
return new AsyncQueryableWrapper<T>(source);
}
}
internal class AsyncQueryableWrapper<T>: IDbAsyncEnumerable<T>, IQueryable<T>
{
private readonly IQueryable<T> _source;
public AsyncQueryableWrapper(IQueryable<T> source)
{
_source = source;
}
public AsyncQueryableWrapper(IEnumerable<T> source)
{
_source = source.AsQueryable();
}
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public Expression Expression => _source.Expression;
public Type ElementType => _source.ElementType;
public IQueryProvider Provider => new AsyncQueryProvider<T>(_source.Provider);
}
internal class AsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T>
{
public AsyncEnumerable(IEnumerable<T> enumerable)
: base(enumerable)
{ }
public AsyncEnumerable(Expression expression)
: base(expression)
{ }
public IDbAsyncEnumerator<T> GetAsyncEnumerator()
{
return new AsyncEnumerator<T>(this.AsEnumerable().GetEnumerator());
}
IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
{
return GetAsyncEnumerator();
}
IQueryProvider IQueryable.Provider => new AsyncQueryProvider<T>(this);
}
internal class AsyncQueryProvider<TEntity> : IDbAsyncQueryProvider
{
private readonly IQueryProvider _inner;
internal AsyncQueryProvider(IQueryProvider inner)
{
_inner = inner;
}
public IQueryable CreateQuery(Expression expression)
{
var t = expression.Type;
if (!t.IsGenericType)
{
return new AsyncEnumerable<TEntity>(expression);
}
var genericParams = t.GetGenericArguments();
var genericParam = genericParams[0];
var enumerableType = typeof(AsyncEnumerable<>).MakeGenericType(genericParam);
return (IQueryable)Activator.CreateInstance(enumerableType, expression);
}
public IQueryable<TElement> CreateQuery<TElement>(Expression expression)
{
return new AsyncEnumerable<TElement>(expression);
}
public object Execute(Expression expression)
{
return _inner.Execute(expression);
}
public TResult Execute<TResult>(Expression expression)
{
return _inner.Execute<TResult>(expression);
}
public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute(expression));
}
public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken)
{
return Task.FromResult(Execute<TResult>(expression));
}
}
internal class AsyncEnumerator<T> : IDbAsyncEnumerator<T>
{
private readonly IEnumerator<T> _inner;
public AsyncEnumerator(IEnumerator<T> inner)
{
_inner = inner;
}
public void Dispose()
{
_inner.Dispose();
}
public Task<bool> MoveNextAsync(CancellationToken cancellationToken)
{
return Task.FromResult(_inner.MoveNext());
}
public T Current => _inner.Current;
object IDbAsyncEnumerator.Current => Current;
}
}
If you don't want to hit the DB, you'll most likely have to provide your own implementation of empty IQuerable that implements IDbAsyncEnumerable. But I don't think it is too hard. In all the enumerators just return null for Current and false for MoveNext. In Dispose just do nothing. Try it. Enumerable.Empty<MyObject>().AsQueryable() has nothing to do with database, it definitely does not implement IDbAsyncEnumerable. You need an implementation that does, according to this.
I had the same problem, and didn't figure out what was happening, but I could solve the issue with this:
public IQueryable<MyObject> GetByNames(IList<string> names)
{
if (names?.Any() != true)
{
return _db.Set<MyObject>().Take(0);
//! or
return _db.MyObjects.Take(0);
}
...
}
From the Autofac documentation I can see how to get all registrations for a class T:
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
But when I only have the Type available, how can I get the equivalent results?
public Array ResolveAll(Type service)
{
return _container.Resolve( ???
}
I am trying to implement a wrapper class which has a pre-defined interface.
EDIT
For quick reference, the answer from Matthew Watson (with relevant ideas from David L) is:
public Array ResolveAll(Type service)
{
var typeToResolve = typeof(IEnumerable<>).MakeGenericType(service);
return _container.Resolve(typeToResolve) as Array;
}
Here is an example. I've added asserts to prove that the types returned from ResolveAll<T>(this IContainer self) are the same (and in the same order) as those returned from ResolveAll(this IContainer self, Type type):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Autofac;
using Autofac.Core;
namespace AutofacTrial
{
public abstract class Base
{
public abstract string Name { get; }
public override string ToString()
{
return Name;
}
}
public sealed class Derived1: Base
{
public override string Name
{
get
{
return "Derived1";
}
}
}
public sealed class Derived2: Base
{
public override string Name
{
get
{
return "Derived2";
}
}
}
public sealed class Derived3: Base
{
public override string Name
{
get
{
return "Derived3";
}
}
}
static class Program
{
static void Main()
{
var builder = new ContainerBuilder();
builder.RegisterType<Derived1>().As<Base>();
builder.RegisterType<Derived2>().As<Base>();
builder.RegisterType<Derived3>().As<Base>();
var container = builder.Build();
var array1 = container.ResolveAll(typeof(Base));
var array2 = container.ResolveAll<Base>();
Trace.Assert(array1.Length == 3);
Trace.Assert(array2.Length == 3);
for (int i = 0; i < array1.Length; ++i)
{
Trace.Assert(array1[i].GetType() == array2[i].GetType());
Console.WriteLine(array1[i]);
}
}
public static T[] ResolveAll<T>(this IContainer self)
{
return self.Resolve<IEnumerable<T>>().ToArray();
}
public static object[] ResolveAll(this IContainer self, Type type)
{
Type enumerableOfType = typeof(IEnumerable<>).MakeGenericType(type);
return (object[]) self.ResolveService(new TypedService(enumerableOfType));
}
}
}
The underling implementation is the same
I also used Reflector to look at the implementation of Resolve<IEnumerable<T>>(), and it winds up doing this:
public static TService Resolve<TService>(this IComponentContext context, IEnumerable<Parameter> parameters)
{
return (TService) context.Resolve(typeof(TService), parameters);
}
which calls:
public static object Resolve(this IComponentContext context, Type serviceType, IEnumerable<Parameter> parameters)
{
return context.ResolveService(new TypedService(serviceType), parameters);
}
So the two must be equivalent, since they are implemented that way.
You can invoke _container.Resolve by calling your wrapped method via reflection (MSDN), but in doing so you will lose your compile-time type safety.
public class Container
{
public T[] ResolveAll<T>()
{
return _container.Resolve<IEnumerable<T>>().ToArray();
}
public object ResolveAllGeneric(Type t)
{
MethodInfo method = GetType().GetMethod("ResolveAll")
.MakeGenericMethod(new Type[] { t });
return method.Invoke(this, new object[] { });
}
}
i just created a PCL called Tipcalc>core, the tutorial from witch i am building it is this one . here is
my TipViewModel.cs
using Cirrious.MvvmCross.ViewModels;
namespace TipCalc.Core
{
public class TipViewModel : MvxViewModel
{
private readonly ICalculation _calculation;
public TipViewModel(ICalculation calculation)
{
_calculation = calculation;
}
public override void Start()
{
_subTotal = 100;
_generosity = 10;
Recalcuate();
base.Start();
}
private double _subTotal;
public double SubTotal
{
get { return _subTotal; }
set { _subTotal = value; RaisePropertyChanged(() => SubTotal); Recalcuate(); }
}
private int _generosity;
public int Generosity
{
get { return _generosity; }
set { _generosity = value; RaisePropertyChanged(() => Generosity); Recalcuate(); }
}
private double _tip;
public double Tip
{
get { return _tip; }
set { _tip = value; RaisePropertyChanged(() => Tip); }
}
private void Recalcuate()
{
Tip = _calculation.TipAmount(SubTotal, Generosity);
}
}
}
The problem is that when i cuild this PCL, get the following errors:
Error 1 The type or namespace name 'ICalculation' could not be found (are you missing a using directive or an assembly reference?)
TipCalc.Core
Error 2 The type or namespace name 'ICalculation' could not be found (are you missing a using directive or an assembly reference?)
Altough my interface and class,are right there in the Services Folder,in project.
Calculation.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TipCalc.Core.Services
{
public class Calculation : ICalculation
{
public double TipAmount(double subTotal, int generosity)
{
return subTotal * ((double)generosity) / 100.0;
}
}
}
And ICalculation.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TipCalc.Core.Services
{
public interface ICalculation
{
double TipAmount(double subTotal, int generosity);
}
}
any help please?
You need to add using in Calculation.cs
to Use ICalculation.cs
Using TipCalc.Core.Services;