Hugh
Hugh
CC#
Created by Hugh on 6/10/2024 in #help
✅ Casting to enum when only having a Type object
Does anyone know how it's possible to cast while only having a Type object, and not the actual type at compile time? I've got an enum (MyEnum), and an integer value (value) I want to do the equivalent of this:
object? newValue = (MyEnum)value;
object? newValue = (MyEnum)value;
While only having access to typeof(MyEnum) and not knowing what MyEnum actually is. I had thought I could do this:
object? newValue = Convert.ChangeType(value, typeof(MyEnum));
object? newValue = Convert.ChangeType(value, typeof(MyEnum));
But this errors saying: `System.InvalidCastException: Invalid cast from 'System.Int32' to 'MyEnum'.
4 replies
CC#
Created by Hugh on 12/15/2023 in #help
Previewing IL generated by ILGenerator
After generating a constructor method using a ConstructorBuilder and ILGenerator, how can I preview the full generated IL of the constructor method? I'd like to compare the generated IL with something I can check on sharplab.io or in Rider, as my generated constructor isn't working, and I'd like to figure out what is different.
10 replies
CC#
Created by Hugh on 12/14/2023 in #help
✅ Ensure that subclasses all have to override a specific method?
Is it possible to define a method in a class to say that it must be defined in every subclass? For example, if I have:
public class A
{
public virtual void DoSomething() {}
}

public class B : A
{
public override void DoSomething()
{
base.DoSomething();
}
}

public class C : A
{
}
public class A
{
public virtual void DoSomething() {}
}

public class B : A
{
public override void DoSomething()
{
base.DoSomething();
}
}

public class C : A
{
}
I don't want C to be valid. I can't make DoSomething() in A abstract, as I want to be able to instantiate A. If this isn't possible in the language, then my approach will be to change A to an abstract base class Base with an abstract DoSomething(), and a DoSomethingInternal(), and then inherit A from Base and implement DoSomething() there
8 replies
CC#
Created by Hugh on 12/13/2023 in #help
Using ILGenerator to create and populate a List<string>
I'm currently trying to figure out the ILGenerator procedure to add items to a List. Using www.sharplab.io I can see that this code:
public class C {
public List<String> MyStringList { get; set; } = new List<string>{"a", "b"};
}
public class C {
public List<String> MyStringList { get; set; } = new List<string>{"a", "b"};
}
Generates a constructor that looks like this:
IL_0000: ldarg.0
IL_0001: newobj instance void class [System.Collections]System.Collections.Generic.List`1<string>::.ctor()
IL_0006: dup
IL_0007: ldstr "a"
IL_000c: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<string>::Add(!0)
IL_0011: dup
IL_0012: ldstr "b"
IL_0017: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<string>::Add(!0)
IL_001c: stfld class [System.Collections]System.Collections.Generic.List`1<string> C::'<MyStringList>k__BackingField'
IL_0021: ldarg.0
IL_0022: call instance void [System.Runtime]System.Object::.ctor()
IL_0027: ret
IL_0000: ldarg.0
IL_0001: newobj instance void class [System.Collections]System.Collections.Generic.List`1<string>::.ctor()
IL_0006: dup
IL_0007: ldstr "a"
IL_000c: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<string>::Add(!0)
IL_0011: dup
IL_0012: ldstr "b"
IL_0017: callvirt instance void class [System.Collections]System.Collections.Generic.List`1<string>::Add(!0)
IL_001c: stfld class [System.Collections]System.Collections.Generic.List`1<string> C::'<MyStringList>k__BackingField'
IL_0021: ldarg.0
IL_0022: call instance void [System.Runtime]System.Object::.ctor()
IL_0027: ret
I'm trying to replicate the setting of MyStringList in my own custom constructor, and I'm getting an error saying that it's an invalid program. Here's my constructor:
Type listType = typeof(List<string>);
ConstructorInfo? listConstructor = listType.GetConstructor(Array.Empty<Type>());
MethodInfo? addMethod = listType.GetMethod("Add");

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, listConstructor);
// Start set list members
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldstr, "a");
il.Emit(OpCodes.Callvirt, addMethod); // I think that the issue is with this line and the same one 3 below
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldstr, "b");
il.Emit(OpCodes.Callvirt, addMethod);
// End set list members
il.Emit(OpCodes.Stfld, fieldBuilder);

ConstructorInfo parentConst = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Array.Empty<Type>(), null) ?? throw new Exception();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, parentConst);
il.Emit(OpCodes.Ret);
Type listType = typeof(List<string>);
ConstructorInfo? listConstructor = listType.GetConstructor(Array.Empty<Type>());
MethodInfo? addMethod = listType.GetMethod("Add");

il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Newobj, listConstructor);
// Start set list members
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldstr, "a");
il.Emit(OpCodes.Callvirt, addMethod); // I think that the issue is with this line and the same one 3 below
il.Emit(OpCodes.Dup);
il.Emit(OpCodes.Ldstr, "b");
il.Emit(OpCodes.Callvirt, addMethod);
// End set list members
il.Emit(OpCodes.Stfld, fieldBuilder);

ConstructorInfo parentConst = parentType.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, Array.Empty<Type>(), null) ?? throw new Exception();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Call, parentConst);
il.Emit(OpCodes.Ret);
3 replies
CC#
Created by Hugh on 12/11/2023 in #help
✅ Setting default values on fields when generating runtime type
Hi all, I've got code here that is generating a run-time type using TypeBuilder, FieldBuilder and PropertyBuilder. I'd like to ensure that fields have certain default values, as if I'd defined them in the class definition. How can I do this? Currently, if an auto property is defined as being a string, when I create an instance of the runtime type, this property is null
10 replies
CC#
Created by Hugh on 11/8/2023 in #help
✅ Creating new cancellation token from multiple other tokens
I've got function that is being passed in a cancellation token, and I want to cancel an inner function call if either this cancellation token is triggered, or another internal one is triggered (due to a timeout). My method looks something like this:
public async Task DoSomethingAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
CancellationTokenSource timeoutCancellationTokenSource = new();
timeoutCancellationTokenSource.CancelAfter(timeout);

// Create someCombinedCancellationToken which will cancel if either cancellationToken is cancelled
// or timeoutCancellationTokenSource is triggered

await DoSomethingElseAsync(someCombinedCancellationToken);
}
public async Task DoSomethingAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
CancellationTokenSource timeoutCancellationTokenSource = new();
timeoutCancellationTokenSource.CancelAfter(timeout);

// Create someCombinedCancellationToken which will cancel if either cancellationToken is cancelled
// or timeoutCancellationTokenSource is triggered

await DoSomethingElseAsync(someCombinedCancellationToken);
}
If there's no way of doing this, then I am thinking that I could do it something like this:
public async Task DoSomethingAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
CancellationTokenSource timeoutCancellationTokenSource = new();
timeoutCancellationTokenSource.CancelAfter(timeout);

Task result = DoSomethingElseAsync(timeoutCancellationTokenSource);
while(!result.IsCompleted)
{
if(cancellationToken.IsCancellationRequested)
{
timeoutCancellationTokenSource.Cancel();
}

await Task.Delay(100);
}
}
public async Task DoSomethingAsync(TimeSpan timeout, CancellationToken cancellationToken)
{
CancellationTokenSource timeoutCancellationTokenSource = new();
timeoutCancellationTokenSource.CancelAfter(timeout);

Task result = DoSomethingElseAsync(timeoutCancellationTokenSource);
while(!result.IsCompleted)
{
if(cancellationToken.IsCancellationRequested)
{
timeoutCancellationTokenSource.Cancel();
}

await Task.Delay(100);
}
}
But it would be nice to know if there's a way of doing this with a combination cancellation token
2 replies
CC#
Created by Hugh on 6/2/2023 in #help
✅ Getting generic type parameters using reflection
Using the reflection system, how can I get at the generic type parameters? I have the following:
public class MyClass<T1, T2> {}

Type myClassType = typeof(MyClass<string, int>);
Type myClassGenericType = myClassType.GetGenericTypeDefinition();
public class MyClass<T1, T2> {}

Type myClassType = typeof(MyClass<string, int>);
Type myClassGenericType = myClassType.GetGenericTypeDefinition();
And from myClassGenericType, I want to get details of what the generic type parameters are (T1 and T2). In the debugger, this information is in GenericTypeParameters on RuntimeType, but this isn't part of Type, and RuntimeType is private, so I can't get at its internals.
4 replies
CC#
Created by Hugh on 5/14/2023 in #help
❔ ✅ Best way to just get not null values from a collection of possibly null values
I've got a List<MyType?>, and I want to filter out all null values and get a List<MyType back. Which of these is preferable (and more idiomatic) for this, or is there a 3rd better way:
List<MyType> validTypes = possiblyNullTypes.Where(item => item is not null).Cast<MyType>().ToList();
List<MyType> validTypes = possiblyNullTypes.Where(item => item is not null).Select(item => item!).ToList();
List<MyType> validTypes = possiblyNullTypes.Where(item => item is not null).Cast<MyType>().ToList();
List<MyType> validTypes = possiblyNullTypes.Where(item => item is not null).Select(item => item!).ToList();
Thanks
32 replies
CC#
Created by Hugh on 4/5/2023 in #help
✅ Converting value to nullable
I've got a point in my code where I've got:
int intValue = 5;
object? value = intValue; // contains a non-nullable value, an int, float, etc
Type type = typeof(int?);

value = ChangeType(value, type);
int intValue = 5;
object? value = intValue; // contains a non-nullable value, an int, float, etc
Type type = typeof(int?);

value = ChangeType(value, type);
I need to write ChangeType, and only have access to value and type. Using Convert.ChangeType() doesn't work here, and throws an exception. How can I convert this value to nullable successfully? Thanks
14 replies
CC#
Created by Hugh on 3/27/2023 in #help
❔ ✅ Lifetime of variable referenced in Func<>
In some of my tests, I'm creating tables as I go, and then dropping the tables at the end of the test fixture. I'm doing this by having a RegisterType function that looks like this:
private readonly List<Func<Task>> _dropTableFunctions = new();

private async Task<bool> RegisterType<T>(Database database) where T : EntityBase, new()
{
async Task DropTableFunction()
{
await database.DropTable<T>();
}

_dropTableFunctions.Add(DropTableFunction);

return await database.RegisterEntityType<T>();
}
private readonly List<Func<Task>> _dropTableFunctions = new();

private async Task<bool> RegisterType<T>(Database database) where T : EntityBase, new()
{
async Task DropTableFunction()
{
await database.DropTable<T>();
}

_dropTableFunctions.Add(DropTableFunction);

return await database.RegisterEntityType<T>();
}
And then in my TearDown function, I iterate over _dropTableFunctions and call each one. My question here is not related to the database side of this, but is to ask whether I'm risking the Database objects having been destroyed by the time these functions are called? Are references from a function like this considered proper references to the variable, or should I also be storing reference to each database instance elsewhere to ensure that it is kept alive?
10 replies
CC#
Created by Hugh on 2/7/2023 in #help
✅ Logging incoming HTTP requests with WebApplication
I've got a route in my app that isn't being triggered properly. I can't currently figure out what's wrong with it. My controller is being constructed, but the method is never called. Is there a way that I can turn on additional logging? I'd initially like to know what JSON is being passed in, and what HTTP action is being called After that, some kind of information as to why it isn't calling the method (parameter don't match, for example) would be really useful. Thanks
8 replies
CC#
Created by Hugh on 1/25/2023 in #help
❔ ✅ Stopping any additional subclassing of a class
I've got the following code:
public abstract class MyBase {}

public class MyType1 : MyBase {}
public class MyType2 : MyBase {}
public abstract class MyBase {}

public class MyType1 : MyBase {}
public class MyType2 : MyBase {}
Is there a way of stopping any other classes subclassing MyBase other than the two here? I need to be able to do these subclasses, but don't want anyone to be able to do any more.
59 replies
CC#
Created by Hugh on 1/18/2023 in #help
❔ ✅ Generics 'where' : Limitations of what types are allows
When I'm specifying what types are allowed, is it possible to say anything about what types are not allowed. For example, I've got 2 use cases here:
class A {}
class B : A {}
class A2 : A {}
class B2 : B {}


// I want to say that T1 is *not* allowed to be a subclass of B
void DoSomething<T1, T2>(T1 val1, T2 val2)
where T1 : A
where T2 : B
{}

// I want to say that T1 and T2 are not allowed to be the same type
void DoSomethingElse<T1, T2>(T1 val1, T2 val2)
where T1 : A
where T2 : A
{}
class A {}
class B : A {}
class A2 : A {}
class B2 : B {}


// I want to say that T1 is *not* allowed to be a subclass of B
void DoSomething<T1, T2>(T1 val1, T2 val2)
where T1 : A
where T2 : B
{}

// I want to say that T1 and T2 are not allowed to be the same type
void DoSomethingElse<T1, T2>(T1 val1, T2 val2)
where T1 : A
where T2 : A
{}
Are either of this possible in C# at compile time?
9 replies
CC#
Created by Hugh on 1/14/2023 in #help
✅ Adding a JsonDerivedType without setting an attribute on the parent class
I'm currently using multiple JsonDerivedType attributes on a parent class so that I can get polymorphic serialization/deserialization. Is there a way that I can register derived types from elsewhere? For example, if I had another .dll with a subclass in, I won't know what the subclass is where I've defined the base class, but if the .dll has a RegisterTypes() function somewhere, is there a way that this function could add this type to the list of derived types?
5 replies
CC#
Created by Hugh on 1/11/2023 in #help
✅ Using Dependency Injection, sharing singletons between builders?
I'm not sure if I'm taking a completely off-the-wall approach to this, so please let me know if I should completely restructure here. I'm currently using a class that implements IHostedService for my program, and then that creates two separate WebApplications (two because they are listening in different directions, with different CORS settings, and one has a Controller, and the other has a SignalR Hub) What this means is that I have three different Builders at different parts of my code - one to create the initial program, and then one each for the two WebApplications. The issue I've hit upon is that I need to share some of the same singletons between these three. Is there a way to do this? Or is there a better way to set up the application across the board? Thanks
2 replies
CC#
Created by Hugh on 1/11/2023 in #help
✅ When using Dependency Injection, how can I pass other parameters into the constructor?
I'm just starting to get my head around the basics of DI. I've got a number of instances that were being manually created, and I'm working to get them shifted over to using DI. Having references to other classes in the constructor makes some kind of sense to me now. However, I'm now wondering if there's a way to pass other values into the constructor. For example, if I have the following, how could I define what version is in the constructor, and is that even possible? If it's not possible, then if it's a nullable type
public class MyService : IHostedService
{
private readonly SemVersion _version;
private readonly ILogger _logger;

public MyService(ILogger<MyService> logger, SemVersion version)
{
_logger = logger;
_version = version;
}

public async static Task Main()
{
SemVersion serviceVersion = new SemVersion(0, 1, 0);

IHostBuilder builder = Host.CreateDefaultBuilder();
builder.ConfigureServices(services =>
{
services.AddHostedService<MyService>();
});

IHost host = builder.Build();
await host.StartAsync();
}

// Other stuff, including StartAsync() and StopAsync()
}
public class MyService : IHostedService
{
private readonly SemVersion _version;
private readonly ILogger _logger;

public MyService(ILogger<MyService> logger, SemVersion version)
{
_logger = logger;
_version = version;
}

public async static Task Main()
{
SemVersion serviceVersion = new SemVersion(0, 1, 0);

IHostBuilder builder = Host.CreateDefaultBuilder();
builder.ConfigureServices(services =>
{
services.AddHostedService<MyService>();
});

IHost host = builder.Build();
await host.StartAsync();
}

// Other stuff, including StartAsync() and StopAsync()
}
Having played a bit more while writing this question, this seems to work, but it only allows one value per type, and it doesn't feel like it's the right way to do it...
services.Add(new ServiceDescriptor(typeof(SemVersion), serviceVersion));
services.Add(new ServiceDescriptor(typeof(SemVersion), serviceVersion));
What's the best approach to this kind of thing? Thanks
22 replies
CC#
Created by Hugh on 1/11/2023 in #help
✅ Specialising a generic method
I've got a generic method that takes a string and uses a TypeConverter to convert it to a specific type. However, when the requested type is bool, I want 0 and 1 to convert to false and true. I was hoping that I'd be able to do this:
private static T? Convert<T>(string input)
{
if(typeof(T) == typeof(bool))
{
return Convert<int>(input) != 0;
}

try
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
return (T?)converter.ConvertFromString(input);
}
catch(NotSupportedException)
{
return default;
}
}
private static T? Convert<T>(string input)
{
if(typeof(T) == typeof(bool))
{
return Convert<int>(input) != 0;
}

try
{
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
return (T?)converter.ConvertFromString(input);
}
catch(NotSupportedException)
{
return default;
}
}
However, I get an error on return Convert<int>(input) != 0; as it says "Cannot implicitly convert type 'bool' to 'T'", even though in this case the if statement has ensured that T is bool. How can I get this to work, either by convincing the compiler that T is bool in that situation, or any other way? Thanks
12 replies
CC#
Created by Hugh on 1/11/2023 in #help
✅ Switching on a type object
Is there a way to do a switch on a type object? I've got a function that takes a type and returns an enum value for specific types. Currently I've had to do it like this:
private static MyValueType GetValueTypeFromType(Type value)
{
if(value == typeof(string))
{
return MyValueType.String;
}

if(value == typeof(bool))
{
return MyValueType.Bool;
}

if(value == typeof(int))
{
return MyValueType.Int;
}

return MyValueType.Invalid;
}
private static MyValueType GetValueTypeFromType(Type value)
{
if(value == typeof(string))
{
return MyValueType.String;
}

if(value == typeof(bool))
{
return MyValueType.Bool;
}

if(value == typeof(int))
{
return MyValueType.Int;
}

return MyValueType.Invalid;
}
However, I'd like to be able to make this code more concise. I could do it with a Dictionary, but if there's a better way of doing this, I'd love to hear it:
Dictionary<Type, MyValueType> valueTypes = new()
{
[typeof(string)] = MyValueType.String,
[typeof(bool)] = MyValueType.Bool,
[typeof(int)] = MyValueType.Int,
};
Dictionary<Type, MyValueType> valueTypes = new()
{
[typeof(string)] = MyValueType.String,
[typeof(bool)] = MyValueType.Bool,
[typeof(int)] = MyValueType.Int,
};
8 replies
CC#
Created by Hugh on 1/9/2023 in #help
✅ Extracting an object from a Utf8JsonReader
I'm currently writing my own JsonConverter, and I've got the writer bit working fine. (simplified example below)
public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
{
writer.WriteString("name", value.Name);
writer.WriteString("value", value.Value);
}
public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerOptions options)
{
writer.WriteString("name", value.Name);
writer.WriteString("value", value.Value);
}
However, I'm struggling a bit to do the opposite of this in Read() I have the Utf8JsonReader object in Read(), but the only thing that I can figure out is how to get a direct value from the reader, and can't get values by key from it. What am I missing here? Thanks
6 replies
CC#
Created by Hugh on 1/8/2023 in #help
✅ Sharing a Func alias between files
Hi all, I've currently got the following at the top of 2 different files:
using MyFunc = Func<string, string, int, float, string>;
using MyFunc = Func<string, string, int, float, string>;
Because it's a using, as I understand it, it's only available to that one file. How can I do something where I only define this function type in one place, and can use it in multiple files?
5 replies