Implicit Conversion Not Working for Dynamic Type - c#-4.0

I am running into a problem when trying to implicitly convert one of my dynamic types. There are two assemblies with definitions similar to the following:
Configuration.dll:
public class ConfigurationValue : DynamicObject
{
public ConfigurationValue(string val)
{
//...
}
//...
public static implicit operator string(ConfigurationValue val)
{
return val.ToString();
}
}
There is another class in this dll called Configuration with a member variable called Instance (to make the class singleton). This variable holds the ConfigurationValue instances in a dictionary and is of type dynamic. This allows me to do this following:
Server.dll:
//...
if (Configuration.Instance.SecurityLevel != "Insecure")
{
//...
}
Assuming that SecurityLevel is in the dictionary.
This if statement appears verbatim in my code and always fails with the following error:
{"Operator '!=' cannot be applied to operands of type 'System.Dynamic.DynamicObject' and 'string'"}
Previously, when these two classes were in the same assembly, this code worked fine. Can anyone tell me what I'm doing wrong here?
Thanks,
Max

Solved the problem, a little embarrassing actually, I forgot to change the container class for ConfigurationValue (e.g. the type of Configuration.Instance) from internal to public when I moved it to the new assembly, so of course the type couldn't be resolved and the implicit conversion was not found

Try
var SecurityLevel = new ConfigurationValue("Insecure");

Related

TS: Cannot invoke an expression whose type lacks a call signature when defined dynamically, but it works

I'm still quite new to typescript, so please be gentle with me if I'm doing something with no sense for this technology!
The problem that I'm trying to solve is having a dynamic way to define how my application errors should be structured, but leaving to the users the faculty to enrich the messages.
So I tried to create this logic in a module that could be extended easily from the application, but I'm currently facing the problem:
Error:(35, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
What I thought it was a good idea (but please tell me if I'm wrong), was to use a register and a map to have the possibility to extend this mapping every time I want. So I created my ErrorMessage interface to be like the following:
export interface ErrorMessage {
actionMessage: string;
actionSubject: string;
originalErrorMessage?: string;
toString: () => string;
}
and a register for these, called ErrorResponseRegister, as it follows:
export enum defaultErrors {
ExceptionA = 'ExceptionA',
ExceptionB = 'ExceptionB',
}
export class ErrorResponseRegister {
private mapping: Map<string, ErrorMessage>;
constructor() {
this.mapping = new Map()
.set(defaultErrors.ExceptionA, exceptionAErrorMessage)
.set(defaultErrors.ExceptionB, exceptionBErrorMessage);
}
}
So at the end, every ErrorMessage function should look like:
export function exceptionAErrorMessage(originalErrorMessage?: string): ErrorMessage {
return {
enrichment1: "Something happened",
enrichment2: "in the application core",
originalErrorMessage: originalErrorMessage,
toString(): string {
return `${this.enrichment1} ${this.enrichment2}. Original error message: ${originalErrorMessage}`;
},
};
}
Please note I haven't used classes for this ones, as it doesn't really need to be instantiated
and I can have a bunch of them where the toString() method can vary. I just want to enforce the errors should have an enrichment1 and enrichment2 that highlight the problem in a better way for not-technical people.
So, now, back to code. When I'm trying to use the exceptionAErrorMessage statically, I can't see any problem:
console.log(exceptionAErrorMessage(originalErrorMessage).toString())
But when I try dynamically, using the map defined in the ErrorResponseRegister, something weird happens:
// In ErrorResponseRegister
public buildFor(errorType: string, originalErrorMessage?: string): Error {
const errorMessageBuilder = this.mapping.get(errorType);
if (errorMessageBuilder) {
return errorMessageBuilder(originalErrorMessage).toString();
}
return "undefined - do something else";
}
The code works as expected, the error returned is in the right format, so the toString function is executed correctly.
BUT, the following error appears in the IDE:
Error:(32, 18) TS2349: Cannot invoke an expression whose type lacks a call signature. Type 'ErrorMessage' has no compatible call signatures.
The line that causes the problem is
errorMessageBuilder(originalPosErrorMessage).toString()
Can someone help me to understand what I'm doing wrong?
It looks like your problem is you've mistyped mapping... it doesn't hold ErrorMessage values; it holds (x?: string)=>ErrorMessage values:
private mapping: Map<string, (x?: string) => ErrorMessage>;
What's unfortunate is that you initialize this variable via new Map().set(...) instead of the using an iterable constructor argument.
The former returns a Map<any, any> which is trivially assignable to mapping despite the mistyping. That is, you ran smack into this known issue where the standard library's typings for the no-argument Map constructor signature produces Map<any, any> which suppresses all kinds of otherwise useful error messages. Perhaps that will be fixed one day, but for now I'd suggest instead that you use the iterable constructor argument, whose type signature declaration will infer reasonable types for the keys/values:
constructor() {
this.mapping = new Map([
[defaultErrors.ExceptionA, exceptionAErrorMessage],
[defaultErrors.ExceptionB, exceptionBErrorMessage]
]); // inferred as Map<defaultErrors, (orig?: string)=>ErrorMessage>
}
If you had done so, it would have flagged the assignment as an error with your original typing for mapping (e.g., Type 'Map<defaultErrors, (originalErrorMessage?: string | undefined) => ErrorMessage>' is not assignable to type 'Map<string, ErrorMessage>'.) Oh well!
Once you make those changes, things should behave more reasonably for you. Hope that helps; good luck!
Link to code

Dynamic type inferring, or custom VariableScope. How is it done correctly?

I have a scripting system where depending on where the script is executed you have access to different variables. I also want to have inferred types for a type of Auto-Completion for the script editor.
But when the types are inferred during the compile phase, I have no way of giving a Binding which explains to the compilation phase what types those dynamic variables have.
I have currently solved this by:
Not compiling the code with either #TypeChecked nor #CompileStatic but later manually running a subclassed StaticCompilationVisitor on the dynamically typed codebase and manually filling in the StaticTypesMarker.INFERRED_TYPE inside visitVariableExpression() for the dynamic variables that I know exists.
However, this seems like the wrong way to go about it, and I would actually like to work with the VariableScope instead. But it seems to be under rough lockdown inside the VariableScopeVisitor, so it's difficult to pop in a CustomVariableScope that dynamically does the lookups. I have managed to do this with reflection, replacing the VariableScopeVisitor inside CompilationUnit and currentScope and such inside VaribleScopeVisitor. It works, but I don't like working against hard-coded private field names.
This might be a long-winded way of asking: Is there an official way of handling a situation of static typing with dynamic variables? I cannot do this by setting scriptBaseClass for reasons too complex to explain here.
If the question is unclear, please tell me and I'll try to edit in better explanations.
The answer was to add a GroovyTypeCheckingExtensionSupport to a StaticTypeCheckingVisitor and then use visitClass on the first ClassNode of the CompilationUnit.
final ClassNode classNode = this.compilationUnit.getFirstClassNode();
final StaticCompilationVisitor visitor = new StaticCompilationVisitor(this.sourceUnit, classNode);
visitor.addTypeCheckingExtension(new MyGroovyTypeCheckingExtensionSupport(visitor, this.compilationUnit));
visitor.visitClass(classNode);
visitor.performSecondPass();
And create something like the class below:
private static class MyGroovyTypeCheckingExtensionSupport extends GroovyTypeCheckingExtensionSupport {
private static final ClassNode CLASSNODE_OBJECT = ClassHelper.make(Object.class);
public MyGroovyTypeCheckingExtensionSupport(StaticTypeCheckingVisitor typeCheckingVisitor, CompilationUnit compilationUnit) {
super(typeCheckingVisitor, "", compilationUnit);
}
#Override
public boolean handleUnresolvedVariableExpression(VariableExpression vexp) {
final ClassNode type = this.getType(vexp);
if (type == null || type.equals(CLASSNODE_OBJECT)) {
if (vextp.getName().equals("something")) {
this.storeType(vexp, ClassHelper.make(SomeClass.class));
return true;
}
}
return false;
}
}

TypeScript Cannot find namespace despite Variable being in same Class

I'm trying to define Callbackdefinitions to make it easier to work with many callbacks in my Node.js project.
My database.ts file looks like that:
export default class Database {
//Export the enums
public static LoadObjectResponse = LoadObjectResponse;
//Export Callback definitions
public static loadObjectCallback: (resultCode: Database.LoadObjectResponse) => void;//ERROR
...
}
enum LoadObjectResponse {
ERROR_ON_LOADING, //"Error on Loading Object.",
OBJECT_NOT_FOUND //"Object not found."
}
So I want a loadObjectCallback defined, that says that the parameter has to be of the enum Type LoadObjectResponse. But when I try to do it like that, the compiler always gives the error
Cannot find namespace "Database"
I don't understand why it gives me the error, the variable itself is in the definition of Database, why doesn't it work?
It gives me the same error when I try to use it in Classfunction definitions:
public static loadObject(MongoModel, searchObject, callback: Database.LoadObjectResponse) {//ERROR namespace Database not found
Again Error:
Cannot find namespace "Database"
Inside of functions in the Database class calling
Database.LoadObjectResponse
works flawlessly, why doesn't it work in variable definitions?
Cannot find namespace "Database"
This is a common learning curve issue. You need to understand and be comfortable with the intutive concept of declaration spaces : https://basarat.gitbook.io/typescript/project/declarationspaces
Things are distinct in the type declaration space or in the variable declaration space.
In your case public static LoadObjectResponse is a variable hence cannot be used as a type (error on annotation usage : Database.LoadObjectResponse).
Fix
Please don't treat a class as a namespace. The file is a module.
export class Database {
//Export Callback definitions
public static loadObjectCallback: (resultCode: LoadObjectResponse) => void;//ERROR
}
export enum LoadObjectResponse {
ERROR_ON_LOADING, //"Error on Loading Object.",
OBJECT_NOT_FOUND //"Object not found."
}
Also beware of export default : https://basarat.gitbook.io/typescript/main-1/defaultisbad
It's because Database.LoadObjectResponse is a property and not a type. You can't use properties as types.
To make this work, change it to use the type of the property:
static loadObjectCallback: (resultCode: typeof Database.LoadObjectResponse) => void;
Or refer directly to the enum type of LoadObjectResponse:
static loadObjectCallback: (resultCode: LoadObjectResponse) => void

Optional arguments on interface and class can conflict

I have just come across an interesting gotcha where optional arguments on an interface and the implementing class can conflict.
I found this out the hard way (school boy error) whilst experimenting. You cannot spot it in the debugger and I assumed it was me messing up the dependency injection.
I'm guessing this is so an alternative interface can give a differing view on what default behaviour should be?
Is there a compiler warning or style cop rule to help point this out?
public interface MyInterface
{
MyStuff Get(bool eagerLoad = true); //this overrules the implementation.
}
public class MyClass : MyInterface
{
public MyStuff Get(bool eagerLoad = false) //will still be true
{
//stuff
}
}
Remember default arguments are a compile-time feature. The compiler picks up the default argument based on the static type of the reference in question and inserts the appropriate default argument. I.e. if you reference is of the interface type you get one behavior but if the reference is of the class type you get the other in your case.

class properties are not available in generic method c#

I am calling a generic method with two different classes as below:
FillDataPointsInOrder<Metrics>(dataPoints.Where(O => O.SortOrder != null).OrderBy(O => O.SortOrder));
FillDataPointsInOrder<Metric>(angieStatsCmp.GetDataColumns());
private void FillDataPointsInOrder<T>(IEnumerable<T> dataPoints)
{
foreach (T dpoint in dataPoints)
{
if (!dpoint.IsPhone)
FillDrp(this.EmailDrp, dpoint.Name, dpoint.MetricId.ToString(), dpoint.VName);
if (dpoint.IsPhone && this.IsPhoneShop)
FillDrp(this.PhoneDrp, dpoint.Name, dpoint.MetricId.ToString(), dpoint.VName);
}
}
in "FillDataPointsInOrder" method I am getting compile errors :
'T' does not contain a definition for 'IsPhone' and no extension method 'IsPhone' accepting a first argument of type 'T' could be found (are you missing a using directive or an assembly reference?)
Same errors for Name , MetricId and VName properties.
Not sure why T is not able to access properties of Metrics and Metric.
If I remove the code from generic method and write it directly in foreach over dataPoints it is working fine.
Can somebody advise what is wrong here?
FillDataPointsInOrder only knows it will be called with a T. T could actually be string, int or anything.
If you want to call properties on T, you will have to use a where constraint.
But in this case it looks like your method does not even need to be generic.
If both Metric and Metrics share a base class or an interface that has the properties you need:
interface IMetric {
bool IsPhone {get; }
}
you could just have:
private void FillDataPointsInOrder(IEnumerable<IMetric> dataPoints)
Note that IEnumerable is covariant, so if Metric is a IMetric, IENumerable<Metric> is a IEnumerable<IMetric>
You need to at least tell the compiler something about T if you want to do that. Do you have an interface that has members like IsPhone, Name, MetricId, etc. that your classes implement?
If so you can add a 'where' constraint to your class definition:
public class Something<T> where T : ISomethingElse
...where ISomethingElse is the interface that implements IsPhone.

Resources