Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Lol I opened a branch to try out the .NET 6 RC and see if there were any issues with our existing code:

quote:

error FS0044: This construct is deprecated. WebRequest, HttpWebRequest, ServicePoint, and WebClient are obsolete. Use HttpClient instead.

Yeah, except I'm using WebRequest to make a FTP call, so I don't think HttpClient is exactly needs-suiting there, guys.

NBD, I could disable the warning, but it's a good excuse to upgrade to FluentFTP which seems to be solid. I wonder if anybody out there is relying on PackWebRequest though...

Adbot
ADBOT LOVES YOU

raminasi
Jan 25, 2005

a last drink with no ice

NihilCredo posted:

Lol I opened a branch to try out the .NET 6 RC and see if there were any issues with our existing code:

Yeah, except I'm using WebRequest to make a FTP call, so I don't think HttpClient is exactly needs-suiting there, guys.

NBD, I could disable the warning, but it's a good excuse to upgrade to FluentFTP which seems to be solid. I wonder if anybody out there is relying on PackWebRequest though...

If you do switch to FluentFTP and you run into anything that looks like this timeout issue please post here or there because it's been driving me crazy!!

Mr Shiny Pants
Nov 12, 2012

Cuntpunch posted:

Classic hot /r/programmerhumor take.

Not really, I was curious why we have a factory instead of just "newing" one up like every other piece of functionality inside the framework. It seems convoluted and complicated for something as simple as making a HTTP request.

Same thing with HttpListener. No, I don't want to have to download 50MB of ASP just so I can open up a HTTP port inside a small service.

When MS see something they want to emulate they also do it to stuff that doesn't actually need changing, but they change it anyway because it doesn't fit with the new paradigm they are aiming for. Oh DI seems popular, let's make everything running through DI frameworks. You want small packages? Let's make everything a package.

And now WebRequest is obsolete?

Ensign Expendable
Nov 11, 2008

Lager beer is proof that god loves us
Pillbug
Has anyone worked with Analysis Services? I'm having an issue where a newly created Server object returns stale data even though all old instances of Server have been disposed.

There are a bunch of "Refresh" and "Update" methods but I'm not sure which are appropriate in my case.

Edit: this doesn't always happen, just often enough to break our tests and make people mad

Ensign Expendable fucked around with this message at 20:53 on Sep 17, 2021

Boz0r
Sep 7, 2006
The Rocketship in action.
We have an ASP.NET Core webapi and sometimes when people add simple functionality they build, run tests and push the code, but they forget to actually start the server up to check for basic runtime errors. How do I make this part of a unit test?

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Boz0r posted:

We have an ASP.NET Core webapi and sometimes when people add simple functionality they build, run tests and push the code, but they forget to actually start the server up to check for basic runtime errors. How do I make this part of a unit test?

That's not a unit test. That's an integration test.

You're looking for an integration test that uses a WebApplicationFactory to stand up a runtime instance that you can then test against.

B-Nasty
May 25, 2005

New Yorp New Yorp posted:

That's not a unit test. That's an integration test.

Or even a smoke test performed by your deployment process. It's good practice to have a 'health check' endpoint that your deployment system (or, yuck, scripts) can call to ensure the server started in the environment it was deployed to.

Polio Vax Scene
Apr 5, 2009



I'm looking at options for extending a .net core program I've written so that users can create libraries that will be loaded up and imported.
Looking at options I see MEF is available in .net core now but I'm not finding a lot of information regarding security.
Where can I get info on restricting what actions are available in the loaded libraries' operations?

mystes
May 31, 2006

Polio Vax Scene posted:

I'm looking at options for extending a .net core program I've written so that users can create libraries that will be loaded up and imported.
Looking at options I see MEF is available in .net core now but I'm not finding a lot of information regarding security.
Where can I get info on restricting what actions are available in the loaded libraries' operations?
I believe that Microsoft completely gave up on the idea of sandboxing assemblies using appdomains so it's never going to be safe to load untrusted assemblies if that's what you mean by security.

Polio Vax Scene
Apr 5, 2009



That is precisely what I meant.
Hmm...so would the next best idea be some sort of lua-like scripting module? Open to suggestions

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Wait, by "program" do you mean a server-side application or a locally-run one?

If it's the former, I would reach straight for jails, containers, or other battle-tested and well-documented isolation techniques at the OS level, instead of obscure .NET runtime features.

If it's the latter, I don't see why policing the user's behaviour should be something your app worries about. By letting them execute arbitrary .NET code you're not letting them do anything they couldn't already do by opening a Powershell console. If they need to be stopped from e.g. establishing connections to unauthorized hosts, that's what sysadmins are for.

Polio Vax Scene
Apr 5, 2009



It's the latter, with the intent being distribution of plug-ins amongst the community that uses the program. Like what's a way to stop someone from making a plug-in that deletes (or attempts to) all the files in their C: drive?
Maybe I just need to have some sort of open source review and master build process instead of letting community members build their own plug-ins?

fankey
Aug 31, 2001

Polio Vax Scene posted:

It's the latter, with the intent being distribution of plug-ins amongst the community that uses the program. Like what's a way to stop someone from making a plug-in that deletes (or attempts to) all the files in their C: drive?
Maybe I just need to have some sort of open source review and master build process instead of letting community members build their own plug-ins?

Out of the box Lua isn't sandboxed and if you are running code from unknown sources by default they have the same access as the user executing your software and can cause all sorts of problems. It's not too difficult to lock down by removing things like os.execute() and a bunch of other 'dangerous' calls. If you want to allow file io from Lua you can modify the source to check sanitize the paths - I've done that and it's not too horrible.

Another approach would be to launch node and use something like vm2 to sandbox.

Mata
Dec 23, 2003
AFAIK this is not exactly a solved problem, but if you're going to help users download and run third party executable code the most important part might be having a solid ToS/EULA.
I've seen for example Space engineers take the route of stripping out pretty much everything from the C# language until you're left with basically linq, but hey, that's something...

Calidus
Oct 31, 2011

Stand back I'm going to try science!
.NET Framework App domains let you explicitly set some security boundaries but they aren’t full proof. If you want to do it with .NET 5, i think you could need to run the “plugin” dlls in a separate process and run it under an account with limited permissions. Basically have a plug-in service that your main app talks to.

nielsm
Jun 1, 2009



Working in .NET 5, is there a way to customize the deployment of a desktop (WPF) app?
I want to run the EDITBIN program on the generated DLL and EXE files to set the /swaprun:net flag so it can be run from a network share without locking the files.

I'm not sure what to search for regarding customizing the build/publish steps, but I'm open to writing MSBuild XML if that's needed.

nielsm fucked around with this message at 14:18 on Oct 4, 2021

Supersonic
Mar 28, 2008

You have used 43 of 300 characters allowed.
Tortured By Flan
I just had a WPF related question. I have a view which contains tabs, and within some of the tabs I have sub-views containing textboxes. Currently, these text boxes don't expand to the full width of their parent:



It seems that there are TabControl items which contain nested TabItems. Right now, the TabItem in question looks something like:

code:
        <TabItem Name="Notes">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <Image Source="{dx:SvgImageSource Uri='pack:///Resources/Icons/svg/notes.svg'}" Style="{StaticResource IconTab}" />
                    <Label Content="Notes" Style="{StaticResource TitleStyle}" />
                </StackPanel>
            </TabItem.Header>
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                    <Image Style="{StaticResource IconTitle}" Source="{dx:SvgImageSource Uri='pack:///Resources/Icons/svg/notes.svg'}"></Image>
                    <Label Content="Pre-session Notes" Style="{StaticResource TitleStyle}"/>
                </StackPanel>
                <controls:ExtendedTextBox Text="{wpfcore:CultureAwareBinding SessionCache.SessionObject.Strings.PreSessionNotes, UpdateSourceTrigger=LostFocus}" AcceptsReturn="true" Height="300" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Left" Width="600" TextWrapping="Wrap"/>
                <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                    <Image Style="{StaticResource IconTitle}" Source="{dx:SvgImageSource Uri='pack://Resources/Icons/svg/notes.svg'}"></Image>
                    <Label Content="Post-session Notes" Style="{StaticResource TitleStyle}"/>
                </StackPanel>
                <controls:ExtendedTextBox Text="{wpfcore:CultureAwareBinding SessionCache.SessionObject.Strings.PostSessionNotes, UpdateSourceTrigger=LostFocus}" AcceptsReturn="true" Height="300" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Left" Width="600" TextWrapping="Wrap"/>
            </StackPanel>
        </TabItem>
Is there a way I can get them to expand to the full-width of the parent using StackPanel, or do I need to Switch a DockPanel or a grid?

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe

Supersonic posted:

I just had a WPF related question. I have a view which contains tabs, and within some of the tabs I have sub-views containing textboxes. Currently, these text boxes don't expand to the full width of their parent:



It seems that there are TabControl items which contain nested TabItems. Right now, the TabItem in question looks something like:

code:
        <TabItem Name="Notes">
            <TabItem.Header>
                <StackPanel Orientation="Horizontal">
                    <Image Source="{dx:SvgImageSource Uri='pack:///Resources/Icons/svg/notes.svg'}" Style="{StaticResource IconTab}" />
                    <Label Content="Notes" Style="{StaticResource TitleStyle}" />
                </StackPanel>
            </TabItem.Header>
            <StackPanel Orientation="Vertical">
                <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                    <Image Style="{StaticResource IconTitle}" Source="{dx:SvgImageSource Uri='pack:///Resources/Icons/svg/notes.svg'}"></Image>
                    <Label Content="Pre-session Notes" Style="{StaticResource TitleStyle}"/>
                </StackPanel>
                <controls:ExtendedTextBox Text="{wpfcore:CultureAwareBinding SessionCache.SessionObject.Strings.PreSessionNotes, UpdateSourceTrigger=LostFocus}" AcceptsReturn="true" Height="300" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Left" Width="600" TextWrapping="Wrap"/>
                <StackPanel Orientation="Horizontal" Margin="0,0,0,0">
                    <Image Style="{StaticResource IconTitle}" Source="{dx:SvgImageSource Uri='pack://Resources/Icons/svg/notes.svg'}"></Image>
                    <Label Content="Post-session Notes" Style="{StaticResource TitleStyle}"/>
                </StackPanel>
                <controls:ExtendedTextBox Text="{wpfcore:CultureAwareBinding SessionCache.SessionObject.Strings.PostSessionNotes, UpdateSourceTrigger=LostFocus}" AcceptsReturn="true" Height="300" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Left" Width="600" TextWrapping="Wrap"/>
            </StackPanel>
        </TabItem>
Is there a way I can get them to expand to the full-width of the parent using StackPanel, or do I need to Switch a DockPanel or a grid?

You are telling it Width="600" for both of those text boxes. What does it do if you delete those Width attributes?

spaced ninja
Apr 10, 2009


Toilet Rascal
After you remove the width you can set the horizontalalignment to “stretch” to have it fill the space.

https://docs.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement.horizontalalignment?view=windowsdesktop-5.0

Supersonic
Mar 28, 2008

You have used 43 of 300 characters allowed.
Tortured By Flan
Thanks! These suggestions ended up working for the horizontal, now the only issue I'm having is with the vertical. Is there a way I can have that stretch as well? Right now its set to 300 on both boxes, but
if I remove the set height and add VerticalAlignment="stretch" to both they don't expand to fit the parent. Here's what it looks like when I do that.

spaced ninja
Apr 10, 2009


Toilet Rascal
If I’m not mistaken stretch will only work in one direction on a stack layout, the opposite of the stack orientation. You’ll probably have to swap out layouts to a grid or something.

nielsm
Jun 1, 2009



Yep you want to use a grid there for the vertical stack. Set the rows with the labels to height="auto" and the rows with the text boxes to height="1*".

Boz0r
Sep 7, 2006
The Rocketship in action.

New Yorp New Yorp posted:

That's not a unit test. That's an integration test.

You're looking for an integration test that uses a WebApplicationFactory to stand up a runtime instance that you can then test against.

I'm playing around with this and I've run into a small snag. Right now I'm using the IClassFixture<WebApplicationFactory<Startup>> to inject the factory into the constructor and build my client like normal. My problem now is that in my unit tests I inject my mocks with AutoMoqData, and I'd like to be able to do this here too. Is there any way to have something like this:

code:
        
[Theory, AutoMoqData]
public async Task SomeTest(Mock<ISomeService> mock)
{
	...
and have that mock automatically injected into the factory's services?

Hammerite
Mar 9, 2007

And you don't remember what I said here, either, but it was pompous and stupid.
Jade Ear Joe
Is anyone here an expert on MSIX? who has created "related sets"? I am having no luck at all getting this poo poo to work.

"A related set cannot be updated because the updated set is invalid. All packages in the related set must be updated at the same time. (0x80003d17)"

I believe I must be missing something in the main package, but I have no idea what.

LongSack
Jan 17, 2003

I'm getting an unexpected exception that I'm having trouble unraveling.

It's a Blazor Server app, and I'm using ProtectedSessionStorage to store authentication tokens. Because access to this storage requires JavaScript interop, the calls can only be made in the OnAfterRenderAsync method. Which is what I'm doing.

And it worked, for a long time - and is working in several other apps. As best as I can recall, the only change I made between working / not working was replacing the favicon.ico file. Here is the exception text and stack trace:
code:
System.InvalidOperationException: JavaScript interop calls cannot be issued at this time. This is because the component is being statically rendered. When prerendering is enabled, JavaScript interop calls can only be performed during the OnAfterRenderAsync lifecycle method.
         at Microsoft.AspNetCore.Components.Server.Circuits.RemoteJSRuntime.BeginInvokeJS(Int64 asyncHandle, String identifier, String argsJson, JSCallResultType resultType, Int64 targetInstanceId)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, CancellationToken cancellationToken, Object[] args)
         at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args)
         at Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage.ProtectedBrowserStorage.GetAsync[TValue](String purpose, String key)
         at DTrakr.WebUI.Services.StorageService.GetToken(String key)
         at DTrakr.WebUI.Services.StorageService.GetAuthToken()
         at DTrakr.WebUI.Services.StorageService.IsAuthenticated()
         at DTrakr.WebUI.Models.AuthenticationContext.Initialize()
         at DTrakr.WebUI.Models.AuthenticationContextFactory.Create()
         at DTrakr.WebUI.Shared.MainLayout.OnAfterRenderAsync(Boolean firstRender)
Yes, that's right, the exception telling me I need to use OnAfterRenderAsync is being generated in code called from OnAfterRenderAsync. Not sure really how to proceed. Any ideas?

Edit: I figured out what was causing the error, but I have no idea why.

I use an AuthorizationContext class to track authentication state. Because the context requires an async call to initialize itself, I use a factory method to create the context. The factory gets the context via dependency injection (see code below):

C# code:
public class AuthenticationContext
{
    public delegate void AuthenticationStateChangedEventHandler(object sender, AuthenticationStateChangedEventArgs e);

    public event AuthenticationStateChangedEventHandler StateChanged;

    private bool _isAuthenticated;
    public bool IsAuthenticated
    {
        get => _isAuthenticated;
        set
        {
            if (_isAuthenticated != value)
            {
                _isAuthenticated = value;
                StateChanged?.Invoke(this, new AuthenticationStateChangedEventArgs(_isAuthenticated));
            }
        }
    }

    private IStorageService _storageService { get; init; }

    public AuthenticationContext(IStorageService service) => _storageService = service;

    public async Task Initialize() => IsAuthenticated = await _storageService.IsAuthenticated();
}

public class AuthenticationContextFactory : IAuthenticationContextFactory
{
    private readonly AuthenticationContext _context;

    public AuthenticationContextFactory(AuthenticationContext context) => _context = context;

    public async Task<AuthenticationContext> Create()
    {
        await _context.Initialize();
        return _context;
    }
}
If I install the AuthenticationContext as a singleton, I get the exception. If I install it as a scoped service, everything runs just fine. :iiam:

LongSack fucked around with this message at 15:42 on Oct 20, 2021

The NPC
Nov 21, 2010


We have made an app that sends email notifications to users under certain criteria. E.g.: Equipment needs to be returned, certificates expiring. These are set up so if an action is required, and a user doesn't do $thing after $timeperiod, their manager gets CC'd, and eventually we open up a ticket (Service-Now).

Now Management is saying that people "don't read emails" (true), and want some other way to get a more immediate(?) or maybe consistent response. Has any one had success doing something like this before?

Fake edit: The processes that don't escalate to creating a ticket at the end are the ones we are getting complaints about. I'll have to see if that is an option.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

The NPC posted:

We have made an app that sends email notifications to users under certain criteria. E.g.: Equipment needs to be returned, certificates expiring. These are set up so if an action is required, and a user doesn't do $thing after $timeperiod, their manager gets CC'd, and eventually we open up a ticket (Service-Now).

Now Management is saying that people "don't read emails" (true), and want some other way to get a more immediate(?) or maybe consistent response. Has any one had success doing something like this before?

Fake edit: The processes that don't escalate to creating a ticket at the end are the ones we are getting complaints about. I'll have to see if that is an option.

This is a process/people problem, not a programming problem. Trying to solve it with programming will just shift the problem to some other part of the process or some other set of people.

Quebec Bagnet
Apr 28, 2009

mess with the honk
you get the bonk
Lipstick Apathy

The NPC posted:

We have made an app that sends email notifications to users under certain criteria. E.g.: Equipment needs to be returned, certificates expiring. These are set up so if an action is required, and a user doesn't do $thing after $timeperiod, their manager gets CC'd, and eventually we open up a ticket (Service-Now).

Now Management is saying that people "don't read emails" (true), and want some other way to get a more immediate(?) or maybe consistent response. Has any one had success doing something like this before?

Fake edit: The processes that don't escalate to creating a ticket at the end are the ones we are getting complaints about. I'll have to see if that is an option.

I think you answered your question at the end there. The next step after a ticket is tangible consequences for not taking the action or not following up on the ticket.

B-Nasty
May 25, 2005

The NPC posted:

Now Management is saying that people "don't read emails" (true), and want some other way to get a more immediate(?) or maybe consistent response. Has any one had success doing something like this before?

Fake edit: The processes that don't escalate to creating a ticket at the end are the ones we are getting complaints about. I'll have to see if that is an option.

I've written a similar system, and the key is in the targeted escalation.

Instead of CCing the manager, they get a direct (TO) email after X days informing them of their lazy subordinate. After X more days, it gets escalated again to the next level up. Messages are specific about who/when the ball was dropped. The 3 levels, original + 2 increasing managers, is sufficient for my case.

As New Yorp New Yorp said, after a certain point, there's not much you can do. A computer can't hold a gun to someone's head, and if 2 levels of management don't see that it's done, I would argue what you're warning about isn't that important (i.e. nobody gives a poo poo.)

mystes
May 31, 2006

There are some cheap iot lte chips now if you need to add wireless electric shock collars to your web app.

The NPC
Nov 21, 2010


mystes posted:

There are some cheap iot lte chips now if you need to add wireless electric shock collars to your web app.

Yeah but with WFH we will have to ship them the collar and then write docs on how to wear it. Which they won't read :eng99:


New Yorp New Yorp posted:

This is a process/people problem, not a programming problem. Trying to solve it with programming will just shift the problem to some other part of the process or some other set of people.

Thanks for reminding me not everything can be fixed with code.

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost

New Yorp New Yorp posted:

This is a process/people problem, not a programming problem. Trying to solve it with programming will just shift the problem to some other part of the process or some other set of people.

Yes! Yes!


B-Nasty posted:

I've written a similar system, and the key is in the targeted escalation.

Instead of CCing the manager, they get a direct (TO) email after X days informing them of their lazy subordinate. After X more days, it gets escalated again to the next level up. Messages are specific about who/when the ball was dropped. The 3 levels, original + 2 increasing managers, is sufficient for my case.

As New Yorp New Yorp said, after a certain point, there's not much you can do. A computer can't hold a gun to someone's head, and if 2 levels of management don't see that it's done, I would argue what you're warning about isn't that important (i.e. nobody gives a poo poo.)

Yes! Yes!


Responsibility is not something you can enforce in code, in the end it belongs to people needing to be responsible for their tasks. Assign stuff and follow up.

nielsm
Jun 1, 2009



Also look at whether some of those things that need doing can be automated, you mention renewing certificates as one.

Since you do have a service management system, consider if those things that need doing shouldn't go into it, as tasks with a deadline, as soon as it becomes known it needs doing. That should make a clearer audit trail.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

It's also possible that your organization is used to email being for low-priority business, while urgent requests go through a different channel (Slack? SMS? Magical owl?)

In that case, you have two options:

(1) Make your important emails easily distinguishable from the routine crap, most likely via a different sender address, and instruct the users to set urgent notifications when they receive emais from that sender

(2) Interface with whatever your organization is actually using for rapid communication

Before you go with (2), make sure that the communication format is actually the problem, and not just an excuse to dismiss "oh ffs, The NPC is pestering me again about returning the company Bugatti, gently caress him i'll just pretend I didn't see the email if anyone asks".

biznatchio
Mar 31, 2001


Buglord

nielsm posted:

Since you do have a service management system, consider if those things that need doing shouldn't go into it, as tasks with a deadline, as soon as it becomes known it needs doing. That should make a clearer audit trail.

Echoing this. Email is a cesspool, don't ever rely on it as a notification system for actionable tasks. If you have a system for tickets (and you mentioned you have ServiceNow), just skip the informalities and create the ticket there directly, because that's where people already look for work needing to be done. Even if it's a horrible dumpster fire of a ticket system -- as they tend to be -- you want your generated tasks to be where everyone else's are.

insta
Jan 28, 2009
There's also the option of closing the tickets after a period of inactivity, and blaming the ineffective user on it. Public shaming is a powerful tool.

quote:

Ticket #555123 has been closed by some.butthole after 6 days of inactivity. The ticket was assigned to some.butthole on 2021-10-19 and has not been updated in 7 days.

Boz0r
Sep 7, 2006
The Rocketship in action.
I'm using AutoMapper to map a boatload of classes. All these classes inherit from a common abstract class, with only an id and text description, without adding anything more. I'd like to only create maps for the base classes, but I can't seem to get it to work without also creating maps for all the subclasses, so my mapping profile is getting really big. I've looked a bit around but I can't find a good solution to this.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

Boz0r posted:

I'm using AutoMapper to map a boatload of classes. All these classes inherit from a common abstract class, with only an id and text description, without adding anything more.

Well here's your mapping code then:

code:
abstract class Base {
    public int Id { get; init; }
    public string Description { get; init; }    
}

class Derived1 : Base {
    public Derived1(int id, string desc) {
        Id = id; 
        Description = desc;
    }
}

class Derived2 : Base {
    public Derived2(int id, string desc) {
        Id = id; 
        Description = desc;
    }
}

T2 map<T1, T2>(T1 t1) 
    where T1 : Base
    where T2 : Base
    => (T2)Activator.CreateInstance(typeof(T2), t1.Id, t1.Description);

It's not fully type-safe (can't enforce the exact constructor signature) but so is bloody AutoMapper so whatever.

distortion park
Apr 25, 2011


I think you can do a type safe version if you add a parameterless constructor type constraint and make the derived classes mutable. Probably worse than immutable/dodgy construction though

Adbot
ADBOT LOVES YOU

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

pointsofdata posted:

I think you can do a type safe version if you add a parameterless constructor type constraint and make the derived classes mutable. Probably worse than immutable/dodgy construction though

Yeah I know, descriptions are one thing but having mutable Id fields gives the me the creeps.

I found a way to make it acceptable though, by keeping the function as a method in the base class it can just set the init properties as part of the object expression. You still need the parameterless constructor but the properties are immutable so it's just useless rather than dangerous.

code:
abstract class Base {
    public int Id { get; init; }
    public string Description { get; init; }    

    public T Map<T>() where T : Base, new() {
        return new T() { Id = this.Id, Description = this.Description };
    }
}

class Derived1 : Base {
    public Derived1() {}
    public Derived1(int id, string desc) {
        Id = id; 
        Description = desc;
    }
}

class Derived2 : Base {
    public Derived2() {}
    public Derived2(int id, string desc) {
        Id = id; 
        Description = desc;
    }
}

var x = new Derived1(1, "one");
var y = x.Map<Derived2>();
System.Console.WriteLine(y.Id);

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply