50

I am wondering if there are any pros and cons against this style:

private void LoadMaterial(string name)
{
    if (_Materials.ContainsKey(name))
    {
        throw new ArgumentException("The material named " + name + " has already been loaded.");
    }

    _Materials.Add(
        name,
        Resources.Load(string.Format("Materials/{0}", name)) as Material
    );
}

That method should, for each name, be run only once. _Materials.Add() will throw an exception if it will be called multiple times for the same name. Is my guard, as a result, completely redundant, or there are some less obvious benefits?

That's C#, Unity, if anyone is interested.

async
  • 854
  • 3
    What happens if you load a material twice without the guard? Does _Materials.Add throw an exception? – user253751 Jan 22 '15 at 23:49
  • Yes. I should have probably mentioned: _Materials is a dictionary. – async Jan 23 '15 at 06:40
  • 2
    Actually I have already mentioned in throws an exception :P – async Jan 23 '15 at 07:24
  • 9
    Side notes: 1) Consider using string.Format over string concatenation for building the exception message. 2) only use as if you expect the cast to fail and check the result for null. If you expect to always get a Material, use a cast like (Material)Resources.Load(...). A clear cast exception is easier to debug than a null reference exception that occurs later on. – CodesInChaos Jan 23 '15 at 09:05
  • Yeah, I switched to string.Format afterwards. Was too lazy initially. 2) Thanks :)
  • – async Jan 23 '15 at 09:14
  • Personally I would use a assertion here, that still gives a exception when you try to debug this, but wont take up any resources when you build a release. Unless you load materials from a arbitrary source at runtime, then better keep the exception. – Dorus Jan 23 '15 at 09:21
  • It's generally best practice to use the ArgumentException constructor that specifies a parameter name. Even though there's only one parameter in this case, it's a good habit to form. – Nick Jan 23 '15 at 21:22
  • 3
    In this specific case, your callers may also find a companion LoadMaterialIfNotLoaded or ReloadMaterial (this name could use improvement) method useful. – jpmc26 Jan 24 '15 at 00:16
  • This might be nit picky but shouldn't it be an InvalidOperationException instead of an ArgumentException? The argument is fine it's the state (the material is already loaded) which invalidates the call. – Roman Reiner Jan 24 '15 at 04:10
  • It's probably best to leave that discussion for somewhere else, but that's basically the same exception that gets thrown by Dictionary.Add() – async Jan 24 '15 at 07:29
  • That's a poor reason for the exception. Effectively you are propagating an internal implementation feature, if that is the only reason. – itsbruce Jan 24 '15 at 13:46
  • 1
    On another note: This pattern is ok for sometimes adding an item to a list. Do not however use this pattern for filling an entire list because you will run into a O(n^2) situation where with large lists you will run into performance issues. You won't notice it at 100 entries but at 1000 entries you certainly and at 10.000 entries it will be a major bottleneck. – Pieter B Jan 25 '15 at 13:06
  • I'd probably remove the guard and do the Add in a try catch, where I throw whatever exception with a good message, and use the Adds exception as my exceptions inner. – Andy Jan 26 '15 at 00:26
  • Unity IoC or Unity3d engine? https://unity.codeplex.com – Den Jan 26 '15 at 10:46
  • As a rule of thumb, I like to "throw custom exceptions at the shallowest point of the call stack where the origin of such exception can be distinguished". – Kroltan Jan 26 '15 at 13:15
  • 1
    @Den based on the calls I'd this is Unity3D. To the poster, I think you should keep in mind that on occasion Unity3D practices do clash a bit with what general practices (and sometimes for reasons not strictly related to general game programming, but rather "quirks" specific to Unity3D as an engine). I'd say this might be a borderline case of that. – Selali Adobor Jan 26 '15 at 17:39