|
Apologies for the shouting but this is important.
When answering a question please:
- Read the question carefully
- Understand that English isn't everyone's first language so be lenient of bad spelling and grammar
- If a question is poorly phrased then either ask for clarification, ignore it, or mark it down. Insults are not welcome
- If the question is inappropriate then click the 'vote to remove message' button
Insults, slap-downs and sarcasm aren't welcome. Let's work to help developers, not make them feel stupid..
cheers,
Chris Maunder
The Code Project Co-founder
Microsoft C++ MVP
|
|
|
|
|
For those new to message boards please try to follow a few simple rules when posting your question.- Choose the correct forum for your message. Posting a VB.NET question in the C++ forum will end in tears.
- Be specific! Don't ask "can someone send me the code to create an application that does 'X'. Pinpoint exactly what it is you need help with.
- Keep the subject line brief, but descriptive. eg "File Serialization problem"
- Keep the question as brief as possible. If you have to include code, include the smallest snippet of code you can.
- Be careful when including code that you haven't made a typo. Typing mistakes can become the focal point instead of the actual question you asked.
- Do not remove or empty a message if others have replied. Keep the thread intact and available for others to search and read. If your problem was answered then edit your message and add "[Solved]" to the subject line of the original post, and cast an approval vote to the one or several answers that really helped you.
- If you are posting source code with your question, place it inside <pre></pre> tags. We advise you also check the "Encode "<" (and other HTML) characters when pasting" checkbox before pasting anything inside the PRE block, and make sure "Use HTML in this post" check box is checked.
- Be courteous and DON'T SHOUT. Everyone here helps because they enjoy helping others, not because it's their job.
- Please do not post links to your question into an unrelated forum such as the lounge. It will be deleted. Likewise, do not post the same question in more than one forum.
- Do not be abusive, offensive, inappropriate or harass anyone on the boards. Doing so will get you kicked off and banned. Play nice.
- If you have a school or university assignment, assume that your teacher or lecturer is also reading these forums.
- No advertising or soliciting.
- We reserve the right to move your posts to a more appropriate forum or to delete anything deemed inappropriate or illegal.
cheers,
Chris Maunder
The Code Project Co-founder
Microsoft C++ MVP
|
|
|
|
|
Without seeing any code we can only guess what may be wrong. You should run your code in the debugger to see where the error occurs. You can then work backwards to identify why the reference is null.
|
|
|
|
|
Spam, Spam, Spam, Spam!
Lovely Spam! Wonderful Spam!
Lovely Spam! Wonderful Spam!
Spa-a-a-a-a-a-a-am
Spa-a-a-a-a-a-a-am
Spa-a-a-a-a-a-a-am
Spa-a-a-a-a-a-a-am
Lovely Spam! (Lovely Spam!)
Lovely Spam! (Lovely Spam!)
Lovely Spam!
Spam, Spam, Spam, Spam!
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Lobster Thermidor au Crevettes with a mornay sauce served in a Provencale manner with shallots and aubergines garnished with truffle pate, brandy and with a fried egg on top and spam.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Can I replace the egg with a sausage?
"I have no idea what I did, but I'm taking full credit for it." - ThisOldTony
"Common sense is so rare these days, it should be classified as a super power" - Random T-shirt
AntiTwitter: @DalekDave is now a follower!
|
|
|
|
|
Dang, missed again.
|
|
|
|
|
Hello,
I have a VS project to implement a dll.
This dll is a kind of "Master" dll and it should be possible to extend its functionality with "Extension" dlls without touching the "Master" dll.
The "Master" dll should check everytime when it is loaded, what other dlls are available and thus extend or reduce its functionality by itself.
If "Extension" dlls are missing, the "Master" dll should recognize this without any error and function with reduced functionality.
Any hints from your side which approach would make sense here.
|
|
|
|
|
That sounds the wrong way round to me. The base (not master) dll should not have, or even need, any knowledge of extensions. The point of an extension class is to offer extra or enhanced functionality to an application. So the only process that needs to know whether the extensions are present is the application that wants to use its features.
|
|
|
|
|
The "Master" dll (or base dll) is the application in this case. It is a plugin dll for a software where i do not have the source cose and also extends the functionality of that software. So you could consider the base dll as the application.
|
|
|
|
|
That is not something I have ever had to work on.
|
|
|
|
|
Hi,
I have an appliction that loads extensions from a specific folder; each extension is a class that derives from a base class DTF_ComponentBase , which happens to be a UserControl as all extensions need a very similar dialog window. Each extension is built into a separate DLL file. This is the heart of the code that loads those DLL files:
private readonly List<DTF_ComponentBase> DTFlist=new List<DTF_ComponentBase>();
...
DTFlist.Clear();
string folder = Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName);
log("folder=" + folder);
Directory.CreateDirectory(folder);
string[] dlls = Directory.GetFiles(folder, "*.dll");
Exception firstException = null;
List<string> errors = new List<string>();
foreach (string dll in dlls) {
if (dll.Contains("LPplatformDLL.dll")) continue;
try {
log("File: " + dll);
if (dll.Contains("DTF_ComponentBase.dll")) continue;
Assembly asm2 = Assembly.LoadFile(dll);
Type[] types = asm2.GetTypes();
foreach (Type type in types) {
if (type.IsSubclassOf(typeof(UserControl))) {
UserControl uc = (UserControl)Activator.CreateInstance(type);
if (uc is DTF_ComponentBase comp && !comp.Skip) {
DTFlist.Add(comp);
break;
}
}
}
} catch (Exception exc) {
if (firstException == null) firstException = exc;
errors.Add("Error loading "+dll+"; "+exc.Message);
}
}
At the end DTFlist contains all the extensions that were found and instantiated; a foreach loop can then be used to issue commands such as Start, Stop, ... whatever the base class provides.
Hope this helps.
Luc Pattyn [My Articles]
The Windows 11 taskbar is a disgrace; a third-party add-on is needed to reverse the deterioration. I decline such a downgrade.
modified 5 days ago.
|
|
|
|
|
Presumably you have a well designed understanding of what the additional functionality is in general.
There are a number of design patterns that might be useful in structuring the code.
- Chain of responsibility
- Fly weight
- Decorator
- Composite
- Template
As suggested other response you use reflection to load classes dynamically. Those will need either an interface or base class for your code to interact with it. You will need to at least consider dependencies (other dlls required by the dll that is loaded) in that they must be located somewhere. Either load those also dynamically or insure that the application can find them.
AtaChris wrote: with reduced functionality
That is a design and business consideration which cannot be addressed generically. For example perhaps you want to switch out your database driver. But the application cannot operate without any database. Same thing with supporting multiple card card processor interfaces. If you expect two but only find one then that is ok. But if you find none then the application probably cannot continue.
There are ways around failure cases but they add significant complexity and even business risk.
|
|
|
|
|
I'm having trouble getting my mind around how a default method in an interface works.
Picture the below interface and default method implementation:
public interface IClientForm
{
delegate void WindowClosedDelegate(object sender, WindowEventArgs args);
event WindowClosedDelegate OnClosed;
long FormId { get; set; }
UIContextClass UIContext { get; set; }
IClientForm ParentForm { get; set; }
void Window_Closed(object sender, WindowEventArgs args);
}
public static class IClientFormHelper
{
public static void SetUiContext(this IClientForm iClientForm, UIContextClass _UiContext)
{
iClientForm.UIContext = _UiContext;
iClientForm.FormId = _UiContext.AppContext.ClientGetUniqueFormId();
iClientForm.UIContext.AddForm(iClientForm);
iClientForm.OnClosed += iClientForm.UIContext.Window_Closed;
}
} The main problem I see right now is that the default method code never runs. I assume the code is supposed to run as soon as I call the setter for UIContext that's declared in the main interface.
Apparently, this is something I don't understand.
What I want is for every IClientForm window to run the default code whenever the UIContext setter is called for that form, so that each separate window class doesn't need the same code repeated inside of it.
Can someone spot what I've done wrong and point me in the right direction? I sincerely appreciate your time.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
|
Thanks Luc. If you say it's complex, then it must be too far for me to grasp.
I've decided to use the IClientFormHelper class as an extension method call, that I will just have to repeat in my IClientForm window classes.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
Hm. The one link shows there are many aspects to the default implementation inside interfaces, that article is hard to read and understand in one go.
The first answer in the SO link shows how a default property getter could be written; that is simple, and at first glance what you want could be implemented likewise as a default setter.
Luc Pattyn [My Articles]
The Windows 11 taskbar is a disgrace; a third-party add-on is needed to reverse the deterioration. I decline such a downgrade.
|
|
|
|
|
That's one of the major things that stumped me. Since an interface can't contain data members, then if I try to write a default setter, I have nothing to assign it to.
It was at that point that I gave up!
EDIT:
Maybe I should solve the problem by using the inheritance of a base class, rather than trying to stuff it into the interface.
That gives me an idea...
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
You could use properties rather than variables, couldn't you? That is what the example does...
Luc Pattyn [My Articles]
The Windows 11 taskbar is a disgrace; a third-party add-on is needed to reverse the deterioration. I decline such a downgrade.
|
|
|
|
|
Yes I could use properties, but at some point in the call stack, the value must be assigned to a data member in the window instance.
So that's code that must be repeated in each class, unless I derive from a base class.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
|
Richard Andrew x64 wrote: default method in an interface works.
Default interface methods - C# feature specifications | Microsoft Learn[^]
"to add methods to an interface in future versions without breaking source or binary compatibility with existing implementations of that interface."
The feature is a hack which should be avoided if possible.
It does not fit your case. An abstract class is a better starting point for your example.
|
|
|
|
|
Thanks for your advice.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|
|
I may not understand fully, but perhaps something like this?
public interface IMyInterface
{
static IMyInterface Instance = new MyStruct();
int Number { get; set; }
}
record struct MyStruct(int Number) : IMyInterface
{
}
Then you can use it like this
public void DoWork()
{
IMyInterface myInterface = IMyInterface.Instance;
myInterface.Number = 500;
Console.WriteLine(myInterface.Number);
}
|
|
|
|
|
Console.WriteLine doesn't write to the debugger Output window in .NET 8.
It always works in the .NET Framework, but not in the new .NET.
The difficult we do right away...
...the impossible takes slightly longer.
|
|
|
|