using <T>(T obj) with a Linq query - c#

I have the following method
public static async void CheckAndInsert<T>(T obj)
{
var data = AppDelegate.Self.InstanceLive.LoadAllAsync<T>().Result.ToList();
if (data.Count != 0)
{
var theData = data.FirstOrDefault(t => t.id == obj.id);
if (theData == null)
await StoreData(theData);
else
{
if (theData.__updatedAt != obj.__updatedAt)
await UpdateData(theData);
}
}
}
The database contains tables generated from an Azure database, so are guaranteed to always have an id.
In theory, this code should work, but on compilation, I'm getting an error that
Type T does not contain a definition for 'id' and no extension method 'id' of type 'T'
Is there a way to get this code running?

The trouble here is that with this generic method declaration T can be any type, including those that do not provide an Id member. Obviously, your code would break in this case, hence it is disallowed by the compiler.
To get around this, you need to provide generic type constraints to constrain T such that you can be sure it has an Id property.
public static async void CheckAndInsert<T>(T obj) where T:IIdentity
and have your model classes implement IIdentity which might look something like
public interface IIdentity
{
int Id{get;}
}

Related

Roslyn: How to get the ITypeSymbol associated with an identifier?

I'm attempting to write a Roslyn analyzer to detect usages of Enumerable.Count() being called on arrays. Here is the relevant code in my analyzer:
public override void Initialize(AnalysisContext context)
{
context.RegisterSyntaxNodeAction(AnalyzeInvocationExpression, SyntaxKind.InvocationExpression);
}
private static void AnalyzeInvocationExpression(SyntaxNodeAnalysisContext context)
{
var invocation = (InvocationExpressionSyntax)context.Node;
var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
if (!memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
{
return;
}
Debug.Assert(memberAccess != null);
var ident = memberAccess.Name.Identifier;
// Check whether the method is Count() and there is no parameter list before we try to use the Symbol APIs.
if (ident.ToString() != nameof(Enumerable.Count))
{
return;
}
var arguments = invocation.ArgumentList.Arguments;
if (arguments.Count > 0)
{
return;
}
// Make sure that the subject is an array.
var subject = memberAccess.Expression;
var subjectSymbol = context.SemanticModel.GetSymbolInfo(subject).Symbol;
if (subjectSymbol == null)
{
return;
}
// ???
}
I'm stuck trying to determine whether the object that Count() is being invoked on is an array. I scanned the API a bit and I see there is an ILocalSymbol with a Type property, and also an IFieldSymbol with a Type property that will both presumably get you the type of the object. However, I don't know whether the object I'm analyzing is a local/field/result of a method call/etc, so I would expect IFieldSymbol and ILocalSymbol to e.g. share some common base interface, say IVariableSymbol, that offers you the Type without having to know all the possible places the variable could have come from. However, it seems both interfaces derive directly from ISymbol.
Is the best solution just to do something like this?
internal static class SymbolUtilities
{
public static ITypeSymbol GetType(ISymbol symbol)
{
if (symbol is IFieldSymbol)
{
return ((IFieldSymbol)symbol).Type;
}
if (symbol is ILocalSymbol)
{
return ((ILocalSymbol)symbol).Type;
}
...
}
}
You can get the information about the type, using the method GetTypeInfo of the SemanticModel class:
ITypeSymbol subjectType = context.SemanticModel.GetTypeInfo(subject).Type;
You will find more details about it in the article
"Introduction to Roslyn and its use in program development"

c# typeof applied to generic parameter supertype

I have a method, it doesn't have any T parameters.
Unfortunately, C# typeof operator doesnt work on generics as shown bellow.
public static string ToString(object obj)
{
if (obj.GetType() == typeof(List<object>))
{
return "Bug: Never called";
}
if (obj.GetType() == typeof(List<int>))
{
return "Method only works for int lists";
}
return "";
}
Expected output: ToString(List of ints) would return "Bug: Never Called".
Actual output: "Method only works for int lists"
This worked perfectly fine in Java. You will say that generics in c# don't support this. How can I restructure my code to make "ToString(object)" method work for a list of objects?
Requirements : You cannot modify the method's signature, only its implementation.
Unfortunately you cannot make "int" class implement an interface. Since int class was written by Microsoft. As such I cannot add a visitor pattern on int type.
Unfortunately, c# typeof operator doesn't work on generics as shown bellow.
Actually, it's quite fortunate that it doesn't work as you expect it to work. Unlike Java, C# differentiates between List<int> and List<object> at runtime, not only at compile time. Type information for generics instantiated with primitive type parameters lets .NET produce more efficient code by avoiding type erasure.
If you would like to test if an object is any generic list, use this check instead:
var objT = obj.GetType();
if (objT.IsGenericType && objT.GetGenericTypeDefinition() == typeof(List<>)) {
...
}
As such I cannot add a visitor pattern on int type.
C# gives you a powerful mechanism for dispatching dynamically without implementing an interface. For example, you can do this:
public static string ToString(object obj) {
var list = obj as IList;
if (list != null) {
foreach (dynamic o in list) {
Process(o);
}
}
}
static void Process(int n) { ... }
static void Process(string s) { ... }
static void Process(object o) { ... }
The above will choose the right implementation of Process based on the run-time type of the object in your list.

The repository pattern and LinqToSql methods

I have an object that encapsulates a linq to sql data context.
It has a method IQuerable<T> FromStore<T> that allows me to get my entities from the appropriate table via linq to sql.
I also have call-through methods to call functions on the data context.
The problem I have now is that I can't use those pass through methods within where clauses because there's no translation to sql. I understand why this is happening, but how can I work around it?
Example code:
In my repository class:
public class AquaReportsRepository : LinqToSqlRepository<int>, IAquaReportsRepository
{
public bool IsPhysicalItem(string itemNumber)
{
return _UnderlyingDataContext.Aqua_IsPhysicalItem(itemNumber) ?? true;
}
}
Trying to access data from it:
from part in Repository.FromStore<Parts>()
where !(Repository.IsPhysicalItem(part.Item)) // eek, not translation to sql
select part.ItemNumber;
In the past, where I've needed a simple property on a data object, calculated from another property i've used QueryMap to translate the property into an equivalent expression, however I don't think I can do that here as I need to access a datacontext method.
TL;DR: Read the example for point 1. Use the code in QueryMap, making the changes in bold below.
Right, I've managed to work around this using some slight modifications to QueryMap
There were 2 things I needed to get working:
Figure out how to tell querymap to call a method that uses the data context?
Figure out how to get querymap to pick up the attribute defined on a class, when being accessed via an interface.
The first part was fairly simple:
private static readonly ExpressionMethod<Func<AquaReportsRepository, string, bool>> _IsPhysicalItem =
ExpressionMethod.Create((AquaReportsRepository ardc, string i) => ardc._AquaReportsDC.Aqua_IsPhysicalItem(i) ?? true);
[MapToExpression("_IsPhysicalItem")]
public bool IsPhysicalItem(string itemNumber)
{
return _IsPhysicalItem.Invoke(this, itemNumber);
}
The key here is to simply use a function that takes the object itself as the first argument (AquaReportsRepository in this case) in addition to the normal other argument(s).
The second part however required some (fairly minor) changes to MappedQueryVisitor.cs. in both cases only a single if statement (with statements inside!).
Replace the existing GetLambda method with this:
private LambdaExpression GetLambda(Expression receiver, MemberInfo member) {
LambdaExpression exp;
if(!_mappings.TryGetValue(member, out exp)) {
exp = _mappingLookup(member);
if(null == exp) {
var attr = (MapToExpressionAttribute) member.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
// Added by me to deal with interfaces
if (null == attr)
{
if (null != receiver)
{
// member could be an interface's member, so check the receiver.object type
if (receiver.NodeType == ExpressionType.Constant)
{
var receiverType = ((ConstantExpression)receiver).Value.GetType();
var receiverMemberInfo = receiverType.GetMembers().Where(mi => mi.Name == member.Name).SingleOrDefault();
if (null != receiverMemberInfo)
{
attr = (MapToExpressionAttribute)receiverMemberInfo.GetCustomAttributes(typeof(MapToExpressionAttribute), true).FirstOrDefault();
member = receiverMemberInfo;
}
}
}
}
if(null != attr) {
exp = GetLambdaFromAttribute(receiver, member.DeclaringType, attr);
}
}
_mappings.Add(member, exp);
}
return exp;
}
This change means that if we have a member MethodInfo object representing an interfaces method we will recognise that and try and get the actual MethodInfo of the concrete type we're working with (defined by the constant expression).
Now it correctly picks up the MapToExpressionAttribute attribute on the implementing class, given the MemberInfo of an interface.
The next issue though is with VisitMethodCall, where having got the replacement expression to invoke from the attribute it fails because the argument expression is the interface type, by the method we're invoking requires the implementing class.
This last code change corrects that.
Change the CollectArguments method to this:
private static IEnumerable<Expression> CollectArguments(MethodCallExpression m) {
IEnumerable<Expression> args = m.Arguments;
if (!m.Method.IsStatic)
{
var objectExpression = m.Object;
// Added by me, to deal with interfaces
if (objectExpression.NodeType == ExpressionType.Constant)
{
var objectConstExpression = ((ConstantExpression)objectExpression);
if (objectConstExpression.Type.IsInterface)
{
objectExpression = Expression.Constant(objectConstExpression.Value);
}
}
args = Enumerable.Repeat(objectExpression, 1).Concat(args);
}
return args;
}

Inconsistent accessibility issue

I'm getting the following error:
Inconsistent accessibility: parameter type 'RR.DAL.LINQSqlCLient.StaticReport' is less accessible than method 'RR.BLL.AuditTrail.InsertStaticReportAudit(RR.DAL.LINQSqlCLient.StaticReport, string)'
D:\My Projects\ASP Projects\Development\RapidReportTool\Working Directory\App_Code\BLL\AuditTrail.cs
This is my code:
public static void InsertStaticReportAudit(StaticReport staticReport, string filterString)
{
if (System.Web.HttpContext.Current.Session["AuditTrail"] != null)
{
AuditTrail CurrAuditTrail = (AuditTrail)System.Web.HttpContext.Current.Session["AuditTrail"];
AuditTrailReports auditTrailReport = new AuditTrailReports();
auditTrailReport.ID = AuditTrailReports.Insert(CurrAuditTrail.ID, staticReport.ID, filterString, DateTime.Now, true);
System.Web.HttpContext.Current.Session["AuditTrailReport"] = auditTrailReport;
}
}
The parameter StaticReport class:
partial class StaticReport
{
public bool BelongsToReportCategory(int reportCategoryID)
{
//If there is an entry StaticReport_ReportCategories junction table,
//then this static report belongs to the report category
RapidReportDataContext db = new RapidReportDataContext();
var query = from sr_sc in db.StaticReport_ReportCategories
where sr_sc.StaticReportID == this.ID && sr_sc.ReportCategoryID == reportCategoryID
select sr_sc;
if (query.Count() > 0)
return true;
else
return false;
}
}
Not sure why I'm getting this error. Please help. Thank you.
It is quite literal: the type StaticReport is not public.
Since it's a partial class you may have to look at both declarations, the 'main' declaration should use the public modifier.
The default access level is internal and you cannot use an internal type in the signature of a public method. It would be impossible to call.
You have a public method InsertStaticReportAudit having a parameter with type StaticReport. This type is not public. A caller outside your assembly would not be able to call the method and that is why the compiler doesn't accept it.
You have to make StaticReport public or InsertStaticReportAudit non-public.

Dynamic type passing and instantiation -- how?

EDIT: changed Activator, still doesn't work.
So I'm pretty (very) new to C# and I'm pretty sure this is a dupe, but I've looked through the previous questions and I still can't work out all the points.
I am trying to reduce code smell by replacing some repeated code with a map over a generic list. Specifically, I have code that looks like
var fooNode = node as IFoo;
var barNode = node as IBar;
var bazNode = node as IBaz;
...
if(fooNode != null)
return new FooThing();
if(barNode != null)
return new BarThing();
if(bazNode != null)
return new BazThing();
...
and I want to generalise it.
Here's my attempt:
var types = new Dictionary<Type, Type>
{
{typeof(IFoo), typeof(FooThing)},
{typeof(IBar), typeof(BarThing)},
...
}
foreach(var entry in types)
{
var castNode = node as entry.Key;
return Activator.CreateInstance(entry.Value);
}
Naturally, it doesn't work: The type or namespace name 'entry' could not be found (are you missing a using directive or an assembly reference?). Can you help? Is this sort of thing even possible in C#?
How about this?
foreach(var entry in types)
{
if (node != null && entry.Key.IsAssignableFrom(node.GetType()))
{
return Activator.CreateInstance(entry.Value);
}
}
The problem is that you are confusing generic type parameters with runtime types and in particular the Type class.
If you know what a type will be at compile time then you can use the generic Activator.CreateInstance<T>() method to create an instance of the underlying object - you can use things like type parameters so that this line of code doesn't need to know what the type is, for example:
T CreateObject<T>()
{
return Activator.CreateInstance<T>();
}
However this just passes the buck. In order to call this method the value of the type parameter T must be supplied somewhere - either way the compiler must be able to resolve T to a type (rather than a variable or method).
Conversely the Type class encodes type information at runtime such as its name or the assembly that a type is declared in. Activator.CreateInstance also comes with an overload that allows you to supply an instance of Type:
object CreateObject(Type type)
{
return Activator.CreateInstance(type);
}
In your case it looks like you don't know what the types will be at compile time, so you will be mostly working with the Type class - you can use typeof(MyClass) to get an instance of the the corresponding Type for a class known at runtime, and myObject.GetType() to get type information for an object at runtime.
var types = new Dictionary<Type, Type>
{
{typeof(IFoo), typeof(FooThing)},
{typeof(IBar), typeof(BarThing)},
...
}
foreach(var entry in types)
{
if(entry.Key.IsAssignableFrom(node.GetType()))
return Activator.CreateInstance(entry.Value);
}
return null;
Without understanding clearly your purpose for wanting to return different types from the same operation it will be hard to help. Maybe a little background information into the problem you are trying to solve??
I will assume that since you are attempting to return them interchangeably that fooThing, BartThing and BazThing have the same interface. So I am assuming the following:
public class FooThing : IMyOperations
{
}
public class BarThing : IMyOperations
{
}
public class BazThing : IMyOperations
{
}
You can define the relationship between the classes in another interface
public interface IMyChoice
{
public bool IsSelected { get; }
public IMyOperations GetWorker();
}
public class ChoiceFoo : IMyChoice
{
}
public class ChoiceBar : IMyChoice
{
}
public class ChoiceBaz : IMyChoice
{
}
Now you can say
foreach( var entry in choices)
{
if(entry.IsSelected)
{
return entry.GetWorker();
//Can't remember if i need to break after return..doubt it
}
}

Categories