increase performance func<T> for reflection - .net-core

I am currently working on a piece of code that determines the Type and the Value of a field (all enum's) so we can lookup a translation for the specific enum. I know this is a quite expensive, but i don't see a better solution. Who knows a better fit?
I am using automapper for mapping..
//removed some code
CreateMap<CarModel, CarDTO>
.ForMember(dst => dst.CarBodyType, opt => opt.MapFrom((detail, dto, _, context) => ResolveEnumTranslation(detail, context, car => car.CarBodyType)))
.ForMember(dst => dst.FuelType, opt => opt.MapFrom((detail, dto, _, context) => ResolveEnumTranslation(detail, context, car => car.FuelType)))
.ForMember(dst => dst.GearType, opt => opt.MapFrom((detail, dto, _, context) => ResolveEnumTranslation(detail, context, car => car.GearType)))
//removed more for clearity (there are more enums)
private string ResolveEnumTranslation(CarDetail carDetail, ResolutionContext context, Func<CarDetail, object> property)
{
var selectedEnum = property.Invoke(carDetail);
if (context.Items.TryGetValue(localeKey, out var locale) && locale is string localeString)
{
return carDetail.Country.Translations
.FirstOrDefault(t => t.EnumType == selectedEnum.GetType().Name
&& t.EnumValue == (int)selectedEnum
&& string.Equals(t.CountryLocale?.Locale, localeString, StringComparison.OrdinalIgnoreCase))
?.TranslatedValue ?? property.Invoke(carDetail).ToString();
}
return selectedEnum.ToString();
}
really curious what would be a better approach.

You can make the method generic on the enum type, which allows to pass in the enum value as-is.
This enables to retrieve the enum type via typeof(T) which occurs at compile time, whereas selectedEnum.GetType() occurs at runtime.
You'll have to profile whether this improves performance.
Starting from C# 7.3 you can even use the generic Enum constraint to guard that an enum value gets passed as argument; eg.
where T : Enum
Call the method below via
ResolveEnumTranslation(detail, context, car.GearType)
private string ResolveEnumTranslation<T>(
CarDetail carDetail, ResolutionContext context, T selectedEnum
) where T : Enum
{
var typeName = typeof(T).Name;
if (context.Items.TryGetValue(localeKey, out var locale) && locale is string localeString)
{
return carDetail.Country.Translations
.FirstOrDefault(t =>
t.EnumType == typeName
&& t.EnumValue == Convert.ToInt32(selectedEnum)
&& string.Equals(t.CountryLocale?.Locale, localeString, StringComparison.OrdinalIgnoreCase)
)?.TranslatedValue ?? selectedEnum.ToString();
}
return selectedEnum.ToString();
}

Related

System.Text.Json: Handling Infinity values

From what I can tell, this is the appropriate way to handle double "Infinity" values when using NewtonsoftJson, to avoid those values when serializing.
x.SerializerSettings.FloatFormatHandling = FloatFormatHandling.DefaultValue;
What is the corresponding way to do this when using System.Text.Json?
Without a custom converter you cannot instruct System.Text.Json to write a 0, but - for the record - NaN and the infinities can be handled with JsonNumberHandling.AllowNamedFloatingPointLiterals.
From JsonNumberHandling Enum:
The "NaN", "Infinity", and "-Infinity" String tokens can be read as floating-point constants, and the Single and Double values for these constants will be written as their corresponding JSON string representations.
using System.Text.Json;
var options = new JsonSerializerOptions {
NumberHandling = System.Text.Json.Serialization.JsonNumberHandling.AllowNamedFloatingPointLiterals
};
Console.WriteLine(JsonSerializer.Serialize(Double.NaN, options));
Console.WriteLine(JsonSerializer.Serialize(Double.NegativeInfinity, options));
Console.WriteLine(JsonSerializer.Serialize(Double.PositiveInfinity, options));
Console.WriteLine(JsonSerializer.Deserialize<double>("\"NaN\"", options));
Console.WriteLine(JsonSerializer.Deserialize<double>("\"-Infinity\"", options));
Console.WriteLine(JsonSerializer.Deserialize<double>("\"Infinity\"", options));
prints
"NaN"
"-Infinity"
"Infinity"
NaN
-∞
∞
I ended up using a custom converter.
In startup.cs
.AddJsonOptions(options =>
options.JsonSerializerOptions.Converters.Add(new DoubleInfinityConverter())
);
The converter
internal class DoubleInfinityConverter : JsonConverter<double>
{
public override double Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetDouble();
public override void Write(Utf8JsonWriter writer, double value, JsonSerializerOptions options)
{
if (double.IsNaN(value) || double.IsInfinity(value))
{
writer.WriteStringValue(default(double).ToString());
return;
}
writer.WriteStringValue(value.ToString());
}
}

Moq returns values based on arguments

need small help about returning values based on arguments.
Setup of mocking contains expressions like
mockingObject
.Setup(_=>_.Select(It.IsAny<Expression<Func<Entity, bool>>>(),
It.IsAny<Func<IQueryable<Entity>, IOrderedQueryable<Entity>>>(),
It.IsAny<List<Expression<Func<Entity, object>>>>(), It.IsAny<int?>(), It.IsAny<int?>())))
.ReturnsAsync((Expression<Func<Entity,bool>>,Func<IQueryable<Entity>, IOrderedQueryable<Entity>>,List<Expression<Func<Entity,object>>>,int, int,EntityList());
But I'm getting error that Expression<Func<Entity,bool>> is a type which is not valid give context.
How should I manage Returns?
Need to mock:
public async Task<Result> UpdateNetworkStatus(string id, NetworkStatus status)
{
var network = _unitOfWork.NetworkRepository.SelectListAsync(x => x.Id == id).Result.FirstOrDefault();
if (network == null)
throw new Exception(nameof(network));
network.Status = status;
_unitOfWork.NetworkRepository.Update(network);
var saved = await _unitOfWork.Commit();
if (!saved)
return Result.Failure(new List<string>
{
"Failed to save"
});
return Result.Success();
}
Here I need to mock all possible scenarios.
Here is the example how I had manage to pass args to returns
unitOfWorkMock.Setup(_ => _.EntityRepository.SelectListAsync(It.IsAny<Expression<Func<Entity, bool>>>(),
It.IsAny<Func<IQueryable<Entity>, IOrderedQueryable<Entity>>>(),
It.IsAny<List<Expression<Func<Entity, object>>>>(), It.IsAny<int?>(), It.IsAny<int?>()))
.ReturnsAsync((Expression<Func<Entity, bool>> filter, Func<IQueryable<Entity>, IOrderedQueryable<Entity>> orderBy, List<Expression<Func<Entity, object>>> includes, int? page, int? pageSize) =>
{
if (filter == null)
return Entities();
return Entities().AsQueryable().Where(filter).ToList();
});

ObservableChangeSet wait until list is ready before watching

We have a list page where we can enable or disable a thing™ using a <switch /> That thing™ is toggled with an IsActive flag
public class Thing
{
/* ... */
[Reactive] public bool IsActive { get; set; }
}
Given the following change listener, the idea is when the IsActive property changes (user interaction on a toggle switch), we invoke the _saveItemCommand to save the entity with the new IsActiveState.
public ObservableCollection<Thing> DataObjectList {get;} = new ObservableCollection<Thing>();
public MyClass()
{
_saveItemCommand = ReactiveCommand.CreateFromTask(SaveItemInternal);
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_saveItemCommand);
}
public void OnNavigatingTo()
{
var newItems = _myService.GetNewItems();
DataObjectList.AddRange(newItems);
}
public void OnDestroy()
{
_listWatcher?.Dispose();
}
The problem I'm having is that when I setup the list, The command seems to be invoked on the last item in the list immediately after AddRange is called.
I have tried using .Skip(1) without any luck, but one thing that seems to work but is ugly is .Skip(DataObjectList.Length)
How can I make it so that the command isn't invoked until the first time the user toggles the switch? What is the correct way to setup this listener?
Most likely you'll want to add a Where statement to indicate it should only be called on the IsActivated switch.
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.ToCollection()
.Where(x => x.Any(value => value.IsActive))
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_saveItemCommand);
So the two lines I added are
.ToCollection()
.Where(x => x.Any(value => value.IsActive))
The ToCollection() will convert it into an observable list and the Where will restrict your observable to when there is change of the IsActive values.
You may wish to add a FirstAsync() call if you want it to happen only once after the Where() call.
After the comments on Glenn's answer and some additional conversations with Rodney, here's what finally works.
_listWatcher = DataObjectList
.ToObservableChangeSet()
.AsObservableList()
.Connect()
.WhenPropertyChanged(x => x.IsActive)
.Throttle(TimeSpan.FromMilliseconds(250))
.Skip(1)
.DistinctUntilChanged()
.ObserveOn(RxApp.MainThreadScheduler)
.Select(x => x.Sender)
.InvokeCommand(_createActivationsInternal);

How to preserve the task state when Unwrapping

Please, observe the following trivial .NET 4.5 code:
var tcs = new TaskCompletionSource<object>("Hello");
var t1 = tcs.Task;
var t2 = t1.ContinueWith((t, state) => 0, "Hello");
var t3 = t2.ContinueWith((t, state) => new Task<int>(_ => 0, state), "Hello");
var t4 = t3.Unwrap();
Trace.Assert("Hello".Equals(t1.AsyncState), "t1.AsyncState is broken!");
Trace.Assert("Hello".Equals(t2.AsyncState), "t2.AsyncState is broken!");
Trace.Assert("Hello".Equals(t3.AsyncState), "t3.AsyncState is broken!");
Trace.Assert("Hello".Equals(t4.AsyncState), "t4.AsyncState is broken!");
The last assertion fails, which breaks my code (slightly less contrived than this sample).
My question is how to make the task state survive unwrapping? Is there a way to manually unwrap with the state preservation?
Right now, I do not see any other option, except avoiding the default Unwrap() method. Instead, I found the following workaround to be adequate:
var t4 = t3.ContinueWith((t, _) => t.Result.Result, t3.AsyncState);
I will package it as my own extension method, something like FixedUnwrap():
public static Task<TResult> FixedUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.ContinueWith((t, _) => t.Result.Result, task.AsyncState);
}
IMPORTANT UPDATE
The proposed implementation is wrong! The unwrapped task must continue when the nested task is done, whereas the given version continues when the wrapper task is done. It is very wrong.
Please, find below the correct one (two versions):
public static Task TaskUnwrap(this Task<Task> task)
{
return task.Unwrap().ContinueWith((t, _) =>
{
if (t.Exception != null)
{
throw t.Exception;
}
}, task.AsyncState);
}
public static Task<TResult> TaskUnwrap<TResult>(this Task<Task<TResult>> task)
{
return task.Unwrap().ContinueWith((t, _) => t.Result, task.AsyncState);
}

EF4 Linq return type generic list

I have a C#-4 MVC3 RC test-application which is using Entity Framework 4.
I have this method:
public static List<Content> FetchMenu(int websiteID) {
return (from w in ContextHelper.Current.Websites
where w.WebsiteID == websiteID
select w.Contents).ToList();
}
The objects involved here (Content and Website) are of type EntityObject.
The above function gives compilation error:
Cannot implicitly convert type 'System.Linq.IQueryable<System.Collections.Generic.List<Manager.Models.Content>>' to 'System.Collections.Generic.List<Manager.Models.Content>'. An explicit conversion exists (are you missing a cast?)
w.Contents is an EntityCollection<Content> type collection.
How do I defer the Linq.IQueryable type to return a generic List of type Content?
You need to use parentheses, so that you apply ToList() to the whole query (an object of type IQueryable):
public static List<Content> FetchMenu(int websiteID) {
return (from w in ContextHelper.Current.Websites
where w.WebsiteID == websiteID
select w.Contents).ToList();
}
Otherwise you are calling ToList() on w.Contents only and the select is applied afterwards. It might be clearer if I show the method chaining syntax.
Your version:
ContextHelper.
Current.
Websites.
Where(w => w.WebsiteID == websiteID).
Select(w => w.Contents.ToList());
Correct version:
ContextHelper.
Current.
Websites.
Where(w => w.WebsiteID == websiteID).
Select(w => w.Contents).
ToList();
Edit:
Since w.Contents is a collection, you need to flatten it out by using SelectMany:
public static List<Content> FetchMenu(int websiteID) {
return ContextHelper.
Current.
Websites.
Where(w => w.WebsiteID == websiteID).
SelectMany(w => w.Contents).
ToList();
}
var query = (from w in ContextHelper.Current.Websites
where w.WebsiteID == websiteID
select w.Contents).First();
return query.ToList();
The .First() seems to do the trick... thanks.
Yakimych's answer using SelectMany() is corret. For completeness, here it is using "query comprehension" syntax:
public static List<Content> FetchMenu(int websiteID) {
return (from w in ContextHelper.Current.Websites
where w.WebsiteID == websiteID
from c in w.Contents
select c).ToList();
}

Resources