How do I reuse LINQ aggregation queries on a set of generic C# types with a common shape or interface that is known at compile-time without resorting to black magic dynamic ExpressionBuilder stuff?
For example,
// Each "reportable" class has a decimal property to sum over:
interface IReportable<T> {
Expression<T, decimal> GetSummingExpr(); // no static interface methods :(
}
public static class ReportingExtensions {
public static IQueryable<decimal> Report<T>(this IQueryable<T> qry)
{
return x => x.Sum(qry.GetSummingExpr()); // unsure if interfaces can do this
}
}
var invoices = new Invoice [] { Invoice(100.0M), ... };
var quotes = new Quote [] { Quote(50.0M), ... };
// Ideal use-cases:
var invoiceReport = invoices.AsQueryable().Report();
var quoteReport = quotes.AsQueryable().Report();
// "Reportable" class implementations:
public class Invoice : IReportable<Invoice>
{
public decimal InvoiceTotal { get; set; }
public Expression<Func<Invoice, decimal>> GetTotalExpr()
{
return x => x.InvoiceTotal;
}
}
public class Quote : IReportable<Quote>
{
public decimal QuoteTotal { get; set; }
public Expression<Func<Quote, decimal>> GetTotalExpr()
{
return x => x.QuoteTotal;
}
}
I have tried various approaches, but I can't get it to work without introducing magic strings, ala x.GroupBy("InvoiceTotal").
To my limited knowledge, this stuff is hard because LINQ types are resolved before generics are "rendered" to "concrete types". However, all of the type signatures are known at compile-time, so it seems like something I should be able to coerce the compiler to do.
Related
I would like to find out which of the properties in a source input object, a method has used. After executing the method I need to store in a database which of the properties was used.
The input could be any class with simple types, like this:
public class MyData : IMyData
{
public string A { get; set; }
public int B { get; set; }
public decimal C { get; set; }
}
I thought it could be done using an interface as input to the method, so I can replace the original object with a more advanced object, which stores usage of properties
public interface IMyData
{
string A { get; }
int B { get; }
decimal C { get; }
}
I can then
Create a dynamic object with the same properties
Use ImpromptuInterface to simulate the dynamic object implements my interface
Call my method with this dynamic interface
private static void Main()
{
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
IDictionary<string, object> replacementObject = new ExpandoObject();
replacementObject.Add("FieldsUsed", new List<string>());
foreach (var property in data.GetType().GetProperties())
replacementObject.Add(property.Name, property.GetValue(data));
var replacementInterface = replacementObject.ActLike<IMyData>();
DoStuff(replacementInterface);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)replacementObject["FieldsUsed"])}");
}
private static void DoStuff(IMyData source)
{
Console.WriteLine($"A is {source.A}");
if (source.B > 5)
Console.WriteLine($"C is {source.C}");
}
In the above example I would like to store that fields A and B have been used.
Only I am stuck at how I should store when a property is used by my DoStuff method.
You can write a wrapper like this:
public class ClassWrapper<T>: DynamicObject where T:class
{
private readonly T _obj;
private readonly List<string> _fieldsUsed=new List<string>();
public ClassWrapper(T obj)
{
_obj = obj;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
PropertyInfo propertyInfo = _obj.GetType().GetProperty(binder.Name);
_fieldsUsed.Add(binder.Name);
result = propertyInfo.GetValue(_obj);
return true;
}
public List<string> GetFieldsUsed() => _fieldsUsed;
public T GetWrapper()
{
return this.ActLike<T>();
}
}
and use it like
var data = new MyData { A = "Test", B = 3, C = new decimal(1.2) };
var mc=new ClassWrapper<IMyData>(data);
IMyData wrapped = mc.GetWrapper();
DoStuff(wrapped);
Console.WriteLine($"The method used these fields {string.Join(", ", (List<string>)mc.GetFieldsUsed())}");
If you want to know when a property is used, a Interface like INotifyPropertyChanged can do that for you at runtime. The exampel is only about notification for writes (that actually changed a value), but it would be trivial to expand it to reads and writes. It is not a perfect thing of course, as different executions might follow different code paths that use different properties.
If a function takes a specific type as input, you have to asume that all properties may be relevant. This is especially true for abstract types and interfaces - often the interface exists for this function. If it is one of those two, you can also always provide your own implementation of those Interfaces and Abstract class.
I can not shake the feeling that this is a XY problem.
I have created a custom (readonly) struct to encapsulate a decimal. I am using the struct everywhere, including a public-facing API consumed by various programming languages, and therefore would like to avoid exposing decimal data types.
This shows the relevant parts of the struct:
[ProtoContract(SkipConstructor = false, ImplicitFields=ImplicitFields.None)]
public readonly struct Amount
{
[ProtoIgnore]
public const decimal Scale = 100000m;
[ProtoIgnore]
public decimal Value { get; }
[ProtoMember(1)]
public long ScaledValue { get; }
public Amount(decimal value)
{
Value = value;
ScaledValue = checked((long)(value * Scale).Round(0));
}
public Amount(long scaledValue)
{
Value = scaledValue / Scale;
ScaledValue = scaledValue;
}
public static Amount CreateFrom(long scaledValue) => new Amount(scaledValue);
}
The problem I have is that the ctor is not invoked during deserialization, despite the SkipConstructor=false on ProtoContract, causing only the ScaledValue property to be correctly initialized.
I cannot use a ProtoAfterDeserialization method to set the Value property because the struct is readonly.
I have tried to configure a custom factory method for protobuf-net to use when creating the object, by doing this:
var createFrom = typeof(Amount).GetMethod("CreateFrom", BindingFlags.Public | BindingFlags.Static, null, new[] { typeof(long) }, null);
RuntimeTypeModel.Default[typeof(Amount)].SetFactory(createFrom);
But this invariably results in "InvalidOperationException: Operation is not valid due to the current state of the object.". I have verified that the CreateFrom method is found (so am passing in a valid MethodInfo object).
Any ideas on how to make this work?
struct, and readonly struct in particular, is something that I plan to address more in v3 which has plans for new serializer APIs. In the interim, it isn't a scenario it handles well, but your best bet may be "surrogates" - meaning the serializer largely ignores Amount, using something else more serialization-friendly in its place. This also means you can remove any serializer attributes or APIs from Amount:
using ProtoBuf;
using ProtoBuf.Meta;
static class P
{
static void Main()
{
// only need to do this once, *before*
// serializing/deserialing anything
RuntimeTypeModel.Default.Add(typeof(Amount), false)
.SetSurrogate(typeof(AmountSurrogate));
// test it works
var obj = new Foo { Amount = new Amount(123.45M) };
var clone = Serializer.DeepClone(obj);
System.Console.WriteLine(clone.Amount.Value);
}
}
[ProtoContract]
public class Foo
{
[ProtoMember(1)]
public Amount Amount { get; set; }
}
[ProtoContract]
struct AmountSurrogate
{ // a nice simple type for serialization
[ProtoMember(1)]
public long Value { get; set; }
// operators define how to get between the two types
public static implicit operator Amount(AmountSurrogate value)
=> Amount.CreateFrom(value.Value);
public static implicit operator AmountSurrogate(Amount value)
=> new AmountSurrogate { Value = value.ScaledValue };
}
I have the following code for C++, in a templated class that represents a point. I would like to translate it into C#:
template <class T>
class Point
{
public:
T x;
T y;
T z;
template<typename U> explicit Point(const Point<U> &p)
: x((T)p.x), y((T)p.y), z((T)p.z)
{
}
}
This code enables a point of a given type to be explicitly cast into a point of another type. For example, you may use it something like (admittedly I am not 100% sure on the syntax here, but I get the concept):
Point<float> p;
Point<int> q = (Point<int>)p;
How could I enable the equivalent to this in C#? So far I have:
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
// Constructors exist that accept X, Y, and Z as parameters
public static explicit operator Point<U>(Point<T> p)
{
}
}
This gives an error, however, saying "U" is undefined. This makes sense... but how/where do I define U? Is my approach incorrect?
The difference between my question and the one here is that I am simply changing the underlaying type of the generic class via a cast... not trying to change one generic class into a different generic class with the same underlaying type.
I think the best you can get is this:
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
public Point<U> As<U>()
{
return new Point<U>()
{
X = Convert<U>(X),
Y = Convert<U>(Y),
Z = Convert<U>(Z)
};
}
static U Convert<U>(T t) => (U)System.Convert.ChangeType(t, typeof(U));
}
You cannot define a generic conversion operator, so you need it to be an explicit function. Moreover, a simple cast (U)t won't work, so you need Convert.ChangeType (which will work if your types are numeric).
Usage:
var p1 = new Point<int> { X = 1, Y = 2, Z = 3 };
var p2 = p1.As<double>();
(works as expected).
As far as I know, this kind of generic cast is only allowed in C# if there's some kind of inheritance relationship between T and U.
The closest equivalent would be to define a generic method for the conversion:
public Point<U> To<U>()
{
dynamic p = this;
return new Point<U>((U)p.X, (U)p.Y, (U)p.Z);
}
You cannot convert directly T to U as the compiler has no way to know whether it'll be safe. I use the dynamic keyword to bypass that restriction.
Similar to Kevin's answer, but without dynamic is to use a double cast:
public Point<U> To<U>()
{
return new Point<U>((U)(object)X, (U)(object)Y, (U)(object)Z);
}
Both of our answers don't catch any issues at compile-time.
You cannot declare operators with additional generic type arguments, but you can declare ones to or from specific generic types like Point<int>. C# will also not let you perform arbitrary conversions by casting from or to T.
The least boilerplate heavy option that maintains a modicum of type safety would be to constrain the T parameter to IConvertible:
public class Point<T> where T : IConvertible
{
// ...
public static explicit operator Point<int>(Point<T> point)
{
// The IFormatProvider parameter has no effect on purely numeric conversions
return new Point<int>(point.X.ToInt32(null), point.Y.ToInt32(null), point.Y.ToInt32(null));
}
}
However, this will not prevent users from declaring nonsensical, unsupported types such as Point<DateTime> which will then throw at runtime when attempting a conversion.
You cannot define additional generic type constraints, but you can do something like this, using operators and methods.
public class Point<T>
{
public T X { get; set; }
public T Y { get; set; }
public T Z { get; set; }
public static explicit operator Point<T>(Point<int> v)
{
return v.As<T>();
}
public static explicit operator Point<T>(Point<double> v)
{
return v.As<T>();
}
public static explicit operator Point<T>(Point<float> v)
{
return v.As<T>();
}
public Point<TU> As<TU>()
{
return new Point<TU>()
{
X = ConvertTo<TU>(X),
Y = ConvertTo<TU>(Y),
Z = ConvertTo<TU>(Z)
};
}
private static TU ConvertTo<TU>(T t)
{
return (TU) Convert.ChangeType(t, typeof(TU));
}
}
Usage:
Point<double> d = new Point<double>()
{
X = 10d, Y = 10d, Z = 10d
};
Point<int> i = (Point<int>) d;
Point<float> f = (Point<float>) i;
d = (Point<double>) f;
I am using C# and I thought I finally had the chance to understand a Generic type. I have several strongly typed objects that need the same static method. Rather than create one static method for each type I thought I could make it generic. Something I have never done and really wanted too.
Here is where I invoke it.
bool isDuplicate = Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
Here is my static method which resides in a static class called Utilities.
public static bool GetDuplicates<T>(List<T> pBookings)
{
foreach (var item in pBookings)
{
var myVal = item.bookingId
}
return true;
}
So I want to get at the values within var item inside the foreach loop so I can do comparisons. It's definately passed pBookings because I can hover and they have a .Count() with a collection of my strongly typed object. I am missing something here, possibly a casting process. I was wondering if anyone could advise me where I am coming up short.
var myVal = item.bookingId - I cannot get the bookingID from item because I am lacking in some basic understanding here. bookingId doesn't exist, I just get access to extension methods such as .toString and .equals
ANSWER OF SORTS What I did based on all of your really helpful assistance. I utilised Anderson Pimentel. I'm probably still off the mark but wanted to garner anyones thoughts here.
So basically I have several booking models, all need checking for duplicates. I really wanted to understand Generics in this way. So what I did is. Created a base class.
public class BookingBaseModel
{
public int BookingID { get; set; }
public DateTime BookingStartDateTime { get; set; }
public DateTime BookingEndDateTime { get; set; }
}
Then had my booking classes all inherit whats common to all. Like this...
public class RoomBookingModel : BookingBaseModel
{
public string RoomName{ get; set; }
}
public class vehicleBookingModel : BookingBaseModel
{
public string vehicleName{ get; set; }
}
Then in my utilities static helper I did this..
public static void GetDuplicates<T>(List<T> items) where T : BookingBaseModel
{
foreach (var item in items)
{
int myId = item.ID;
DateTime startDateTime = item.BookingStartDateTime;
DateTime endDateTime = item.BookingEndDateTime;
//Do you logic here
}
}
Then finally did something like this in corresponding controller action.
RoomController...
Utilities.GetDuplicates<RoomBookingModel>(roomBookings);
VehicleController....
Utilities.GetDuplicates<VehicleBookingModel>(vehicleBookings);
Is this basically how we go about using generics in this way?
The compiler has no hint of what type is T. If you have a base class (or an Interface) which has the bookingId attribute, like BaseModel, you can constrain the generic type like the following:
public class BaseModel
{
public int Id { get; set; }
}
public static bool GetDuplicates<T>(List<T> items) where T : BaseModel
{
foreach (var item in items)
{
var myId = item.Id;
//Do you logic here
}
return true;
}
Once you're inside your GetDuplicates method, you have lost all knowledge of the RoomBookingModel type. That's the point of generic methods - they should be able to act on whatever type has been passed in to them, e.g. the logic within them should be generic across any type.
So your foreach loop is fine - you know you've been given a list of something, and you know lists can be iterated. But inside that foreach, item is just a T. You don't know what actual type it is because any type could have been passed in. So it doesn't make sense to access a specific property or method off of item - for example, what if I called GetDuplicates passing in a List<int>? It wouldn't have a bookingId property.
As written by others, you don't know anything of T. A classical solution, used by LINQ (see for example GroupBy) is to have your method receive a delegate that does the key-extraction, like:
public static bool GetDuplicates<T, TKey>(List<T> pBookings, Func<T, TKey> selector)
{
foreach (var item in pBookings)
{
TKey key = selector(item);
}
return true;
}
You then use it like:
GetDuplicates(pBookings, p => p.bookingId);
If you like to use a generic method, you have to provide also a generic method, which is able to generate a key out of the specified type T. Luckily we have LINQ which already provides the needed parts to build your generic method:
internal class Extensions
{
public static IEnumerable<T> GetDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return source.GroupBy(keySelector)
.Where(group => group.Skip(1).Any())
.SelectMany(group => group);
}
public static bool ContainsDuplicates<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector)
{
return GetDuplicates(source, keySelector).Any();
}
}
By having this (and type inference) you can use these methods e.g. by calling:
var hasDuplicates = roomBookings.ContainsDuplicates(item => item.bookingId);
if(hasDuplicates)
{
Console.WriteLine("Duplicates found:");
foreach (var duplicate in roomBookings.GetDuplicates(item => item.bookingId))
{
Console.WriteLine(duplicate);
}
}
I wonder if generics is really the tool for the job here. Your needs would be better served if each of your strongly typed objects shared a common interface.
"I have several strongly typed objects that need the same static method."
In this situation, all of the classes must share a common feature, such as, for instance, a property BookingId.
So, you'd need to formalize this by extracting this common interface:
public interface IBooking
{
int BookingId{ get; }
}
Make sure that every one of your strongly typed items implements the interface:
public class RoomBooking : IBooking
{
//etc...
}
And now make your static method accept IBooking instances:
public static bool GetDuplicates(IEnumerable<IBooking> pBookings)
{
//does pBookings contain items with duplicate BookingId values?
return pBookings.GroupBy(b => b.BookingId).Any(g => g.Count() > 1);
}
An easy read that isn't obfuscated by the unnecessary use of generics.
Since there are no constraints or hints about what T is, the compiler does not have enough information. Consider
bool isDuplicate = Utilities.GetDuplicates<int>(roomBookings);
Clearly an int does not have a bookingId member.
Every possible specific type for T would have to have a common base class or interface that has a bookingId, and even then you would have to add a generic constraint to your method signature to access that.
Perhaps you are looking for something like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Duplicates
{
public static class EnumerableExtensions
{
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter, IEqualityComparer<I> comparer )
{
var hashSet = new HashSet<I>(comparer);
foreach (var item in enumerable)
{
var identity = identityGetter(item);
if (hashSet.Contains(identity)) return true;
hashSet.Add(identity);
}
return false;
}
public static bool HasDuplicates<T, I>(this IEnumerable<T> enumerable, Func<T, I> identityGetter)
{
return enumerable.HasDuplicates(identityGetter, EqualityComparer<I>.Default);
}
}
public class Booking
{
public int BookingId { get; set; }
public string BookingName { get; set; }
}
public class Customer
{
public string CustomerId { get; set; }
public string Name { get; set; }
}
class Program
{
static void Main(string[] args)
{
var bookings = new List<Booking>()
{
new Booking { BookingId = 1, BookingName = "Booking 1" },
new Booking { BookingId = 1, BookingName = "Booking 1" }
};
Console.WriteLine("Q: There are duplicate bookings?. A: {0}", bookings.HasDuplicates(x => x.BookingId));
var customers = new List<Customer>()
{
new Customer { CustomerId = "ALFKI", Name = "Alfred Kiss" },
new Customer { CustomerId = "ANATR", Name = "Ana Trorroja" }
};
Console.WriteLine("Q: There are duplicate customers?. A: {0} ", customers.HasDuplicates(x => x.CustomerId));
}
}
}
I have the following business objects:
public abstract class Product
{
public int Id { get; set; }
public bool OnStock { get; set; }
}
public class ProductForImport : Product
{
public int ImportId { get; set; }
}
public class ProductForExport : Product
{
public int ExportId { get; set; }
public bool IsExportable { get; set; }
public bool IsUsable { get; set; }
public string OtherParam {get; set;}
public static implicit operator ProductForExport(ProductForImport pfi)
{
ProductForExport p = new ProductForExport();
p.Id = pfi.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
so I can convert between the two types:
static void Main(string[] args)
{
ProductForExport pfe = new ProductForExport();
pfe.Id = 1;
pfe.OnStock = true;
ProductForImport pfi = new ProductForImport();
pfi.ImportId = 200;
ProductForExport pfe2 = (ProductForExport)pfi;
}
this works OK.
I have 100.000 ProductsForImport items.
If I understand correctly, if I convert them to ProductsForExport items, I'll have 100.000 +100.000 items in memory - that's reasonable.
My problem is: I have to send these "ProductForExport" objects through JSON services, each service just need some subset of the properties of each type:
servicecall1 should return ProductForExport1{ExportId,IsExportable}
servicecall2 should return ProductForExport2{ExportId,IsUsable}
Question: should I write an implicit conversion similar to the above example for these new types - ProductForExport1 and ProductForExport2 (so basically create 100.000+100.000 new objects)
or
somehow can I just "hide" the unwanted properties with some magic from the original type without the need to create new instances?
thanks,
b.
If you ned such kind of decoupling and separation of entities - you can create DTO object along with each business object and use DTO to communicate with Service.
But if you have a lot of business entities consider an other approach to avoid maintenance hell.
public sealed class ExportProductDto
{
public(ProductForExport exportProduct)
{
// initialize fields
this.ExportId = exportProduct.ExportId;
}
public int ExportId { get; private set; }
}
BTW,
An overkill solution with operator overload, use Adapter pattern to convert between product types
To decouple adapting from entities itself implement following interface your self:
public interface IProductAdapter<TImport, TExport>
{
TImport ToImportProduct(TExport exportProduct);
TExport ToExportProduct(TImport importProduct);
}
Or an other adapter approach:
// Implement this interface for ProductForImport class
// public class ProductForImport : IExportProductAdapter, Product
public interface IExportProductAdapter
{
ProductForExport ToExportProduct();
}
// Implement this interface for ProductForExport class
// public class ProductForExport : IImportProductAdapter, Product
public interface IImportProductAdapter
{
ProductForImport ToImportProduct();
}
EDIT: Answer to comments
// An example of IExportProductAdapter adapter implementation
public sealed class ProductForImport : Product, IExportProductAdapter
{
public int ImportId { get; set; }
public ProductForExport ToExportProduct()
{
ProductForExport p = new ProductForExport();
p.Id = this.Id;
p.IsExportable = true;
p.ExportId = 0;
return p;
}
}
And then instead of:
ProductForExport pfe2 = (ProductForExport)pfi;
You can do:
ProductForExport pfe2 = pfi.ToExportProduct();
I would create light objects specifically for returning through the service with only the required fields. Then use Automapper or something like that to map them.
I don't recommend using operator overloading if you can avoid it. I have seen many issues where a developer didn't realize when the operator overload was being called and something unexpected happened.
If you are using WCF, you can apply the IgnoreDataMemberAttribute to properties you wish not to serialize.
Have a look at the ScriptIgnoreAttribute to exclude properties from json serialization.
It took me a few reads but I don't think your problem is about implicit conversion as much as how to send data via json right?
If you have your object collections of Import or Export object you can use the JavaScriptSerilizer and some anonymous types to slice and dice what data you send.
You can use Linq to select specific properties of your object in a collection, and define an anonymous type "on-the-fly" to serialize out as a json string like this:
List<ProductForExport> exportList; //the list to export
JavaScriptSerializer jss = new JavaScriptSerializer();
string output = string.Empty;
output = jss.Serialize(new
{
isExportable = True, //static named properties
iTotalProducts = exportList.Count, //dynamic values
productDataArray = exportList //all data in an array object
});
//Or build the result using just a few properties of the collection:
foreach (ExportProduct exProd in exportList)
{
output += jss.Serialize(new
{
exProd.IsExportable,
exProd.ExportID
});
}