I have an interface with a few different concrete implementations. I am trying to give Ninject a default to use and only use the other implementation if a name matches. For instance, I have the following bindings.
Bind<ISomething>().To<DefaultSomething>()
Bind<ISomething>().To<OtherSomething>().Named("55abd8b8-097f-4e1c-8d32-95cc97910604");
What I would like is if the Named section doesn't match, to use the DefaultSomething implementation. When I pass in the explicitly bound guid, it works fine. When I pass in any other guid I get the "No matching bindings are available" exception.
Bind<ISomething>().To<OtherSomething>().Named("55abd8b8-097f-4e1c-8d32-95cc97910604");
Bind<ISomething>().To<DefaultSomething>()
Bind<ISomething>().To<DefaultSomething>()
Bind<ISomething>().To<OtherSomething>().When(ctx => ctx.Service != null && ctx.Service.Name == "55abd8b8-097f-4e1c-8d32-95cc97910604");
I have also tried using .When to check the binding and I have tried reversing the order like below however I am never able to bind unless I pass in the Guid that is explicitly named.
This article seems to indicate that default bindings work, so I must be doing something wrong. Any suggestions?
Edit: Here is a complete example showing the problem I am trying to solve. The desired behavior is for kernel.Get<INumber>("Three").Write() to return "Unknown Number"
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Ninject;
namespace NinjectTest
{
interface INumber
{
string Write();
}
class UnknownNumber : INumber
{
public string Write()
{
return "Unknown Number";
}
}
class One : INumber
{
public string Write()
{
return "1 = One";
}
}
class Two : INumber
{
public string Write()
{
return "2 = Two";
}
}
class Program
{
static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<INumber>().To<UnknownNumber>();
kernel.Bind<INumber>().To<One>().Named("One");
kernel.Bind<INumber>().To<Two>().Named("Two");
Console.WriteLine(kernel.Get<INumber>("One").Write());
Console.WriteLine(kernel.Get<INumber>("Two").Write());
Console.WriteLine(kernel.Get<INumber>("Three").Write());
Console.ReadLine();
}
}
}
You completely missunderstood named bindings:
Giving a binding a name is NOT a condition. You will still get all of them when requesting them without a constraint. Adding a name changes absolutely nothing on its own.
Requesting an instance using a name adds the constraint:
only bindings whose name matches the given one shall be returned
In your case, you gave me an instance whose binding's name is "three". And you expect it to return UnknownNumber, which does not even have a name.
This can be achieved by either
passing a parameter and adding conditions to the bindings that check if the parameter matches, or
passing a constraint that fits the name or the unnamed instance and declare the unnamed one implicit.
Option 1:
public class CustomerIdParameter : Parameter
{
public CustomerIdParameter(string id) : base("CustomerId", (object)null, false)
{
this.Id = id;
}
public string Id { get; private set; }
}
kernel.Bind<ISomething>().To<Default>();
kernel.Bind<ISomething>().To<Other>()
.When(r => r.Parameters.OfType<CustomerIdParameter>()
.Single().Id == "SomeName");
kernel.Get<IWeapon>(new CustomerIdParameter("SomeName")).ShouldBeInstanceOf<Sword>();
I leave it up to you to write the extension methods to make the definition and resolve easier.
Option 2:
Bind<ISomething>().To<Default>().Binding.IsImplicit = true;
Bind<ISomething>().To<Other>().Named("SomeName")
public static T GetNamedOrDefault<T>(this IKernel kernel, string name)
{
return kernel.Get<T>(m => m.Name == null || m.Name == name);
}
But honestly I think what you want to do doesn't seem to be a proper design:
Keep your access to the kernel to an absolute minimum. What you're doing here is a ServiceLocator-like usage of Ninject.
If no binding is available for an expected instance, I'd rather expect an exception than using a default instance because this is a bug.
You can also simply add a condition for your binding to not have a condition, like so:
kernel.Bind<IObject>().To<Object1>().When(
x => x.ParentContext != null && !x.ParentContext.Binding.IsConditional)
.InRequestScope();
kernel.Bind<IObject>().To<Object2>().InRequestScope()
.Named("WCFSession");
When doing a standard Inject without a Name specified, the first binding will be used. When specifying a name, the named binding will be used. It's not the prettiest solution, but it works.
It's quite possible to do this in Ninject, it just doesn't happen to be the way the resolution behaves by default. The IKernel.Get<T> extension does not ask for the "default" binding, it asks for any binding; in other words it does not apply any constraints. If there is more than one matching binding then it throws an exception to that effect.
Try out these two extension methods:
static class KernelExtensions
{
public static T GetDefault<T>(this IKernel kernel)
{
return kernel.Get<T>(m => m.Name == null);
}
public static T GetNamedOrDefault<T>(this IKernel kernel, string name)
{
T namedResult = kernel.TryGet<T>(name);
if (namedResult != null)
return namedResult;
return kernel.GetDefault<T>();
}
}
The first one gets the "default" binding - i.e. whichever one you've bound that has no name. The second one tries to get a named binding, but if it doesn't find that, then it reverts to the default.
Of course, Remo is not wrong either; you should avoid using Ninject or any other container this way unless you have a particularly good reason to. This is the Service Locator (anti-)pattern, not true dependency injection. You should be using the When syntax for conditional bindings, either using complex conditions or just decorating the classes which need special bindings, i.e.:
Bind<IFoo>().To<SpecialFoo>().WhenInjectedInto<ClassThatNeedsSpecialFoo>();
or...
Bind<IFoo>().To<SpecialFoo>().WhenMemberHas<SpecialAttribute>();
class InjectedClass
{
public InjectedClass([Special]IFoo) { ... }
}
That is the right way to handle default and conditional bindings. Named bindings are really only useful when you're trying to implement a factory pattern and you want to wrap the IoC container in your custom factory. That's OK, but please use it sparingly, as you end up throwing away many/most of the benefits of dependency injection that way.
Alternatively, you could actually implement your own activation behaviour and use it to override the default in Ninject - everything is modular and gets shoved into the "Components" collection. But this is not for the faint of heart, so I don't plan on including a detailed tutorial here.
I checked the ParaSwarm's solution and it worked for a simple test project. But in a real project his solution didn't fit. I managed to solve it by the following code:
const string specificServiceName = "For" + nameof(SpecificService);
kernel.Bind<IService>()
.To<DefaultService>()
.When(x => x.Constraint == null || !x.Constraint(new BindingMetadata { Name = specificServiceName }))
.InTransientScope();
kernel.Bind<IService>()
.To<SpecificService>()
.InTransientScope()
.Named(specificServiceName);
PS: my answer does not solve the author's problem, but it can help someone with searching similar problem (as ParaSwarm's answer helps me)
Related
This question already has answers here:
How enumerate all classes with custom class attribute?
(8 answers)
Closed 3 years ago.
I'm working on a command tool in C#, although not for a terminal command-line. I have read the documentation on reflection and attributes but I'm not sure exactly what the "right" way to go about this is.
The problem isn't very complicated, but it needs to be easily extended. I need to just have Commands that are picked up and loaded in where their triggering strings are checked and if they match, methods are called. How I went about it just as a proof-of-concept was:
[System.AttributeUsage(System.AttributeTargets.Class)]
public class CommandAttribute : Attribute
{
public string Name { get; private set; } //e.g Help
public string TriggerString { get; private set; } //e.g. help, but generally think ls, pwd, etc
public CommandAttribute(string name, string triggerStrings)
{
this.Name = name;
this.TriggerString = triggerString;
}
}
Now, I decorated the class and it will implement methods from an interface. Eventually there will be many commands and my idea is to make it easy for someone with minimal programming experience to jump in and make a command.
using Foo.Commands.Attributes;
using Foo.Infrastructure;
namespace Foo.Commands
{
[Command("Help", "help")]
public class Help : IBotCommand
{
// as an example, if the message's contents match up with this command's triggerstring
public async Task ExecuteAction()
}
}
This gets injected into the console app where it will load the commands and get passed messages
public interface ICommandHandler
{
Task LoadCommands();
Task CheckMessageForCommands();
}
Then, everything with a matching attribute will get loaded in and when a message is received, it will check its contents against all CommandAttribute decorated classes' triggering strings, and if it matches, call the method ExecuteAction on that command class.
What I've seen/tried: I understand how to use reflection to get custom attribute data, however I'm confused as to getting the methods and calling them, and how all of this should be configured to be fairly performant with reflection being used. I see CLI tools and chat bots that use a similar method, I just cannot peek into their handlers to see how these get loaded in and I can't find a resource that explains how to go about accessing the methods of these classes. Attributes may not be the right answer here but I'm not sure how else to go about it.
Really, my main question is:
How do I setup The CommandHandler to load all of the attribute-decorated classes and call their methods, and how they should be instantiated within it. I know the second piece may be a bit more subjective but would newing them up be improper? Should they somehow be added to DI?
My solution ended up just using the Activator and lists. I still need to tweak this for performance and run more extensive stress tests, but here is my quick code for it:
// for reference: DiscordCommandAttribute is in Foo.Commands library where all the commands are, so for now it's the target as I removed the base class
// IDiscordCommand has every method needed, so casting it as that means down the line I can call my methods off of it. The base class was just for some reflection logic I was testing and was removed, so it's gone
public void LoadCommands() // called in ctor
{
var commands =
from t in typeof(DiscordCommandAttribute).Assembly.GetTypes()
let attribute = t.GetCustomAttribute(typeof(DiscordCommandAttribute), true)
where attribute != null
select new { Type = t, Attribute = attribute };
foreach (var obj in commands)
{
_commandInstances.Add((IDiscordCommand)Activator.CreateInstance(obj.Type));
_commandAttributes.Add(obj.Attribute as DiscordCommandAttribute);
}
}
There is probably a more sugary way to handle adding the objects to the lists, and some other data structure besides Lists might be more suitable, I'm just not sure if HashSet is right because it's not a direct Equals call. Eventually I will genericize the interface for this class and hide all of this logic in a base class. Still a lot of work to do.
Currently, just putting a stopwatch start before calling LoadCommands shows that the entire load takes 4ms. This is with 3 classes and a pretty anemic attribute, but I'm not too worried about the scale as I want any overhead on launch and not during command handling.
Using some code I wrote for this answer, you can find all types that implement an interface, e.g. IBotCommand, and then retrieve the custom attribute:
public static class TypeExt {
public static bool IsBuiltin(this Type aType) => new[] { "/dotnet/shared/microsoft", "/windows/microsoft.net" }.Any(p => aType.Assembly.CodeBase.ToLowerInvariant().Contains(p));
static Dictionary<Type, HashSet<Type>> FoundTypes = null;
static List<Type> LoadableTypes = null;
public static void RefreshLoadableTypes() {
LoadableTypes = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetLoadableTypes()).ToList();
FoundTypes = new Dictionary<Type, HashSet<Type>>();
}
public static IEnumerable<Type> ImplementingTypes(this Type interfaceType, bool includeAbstractClasses = false, bool includeStructs = false, bool includeSystemTypes = false, bool includeInterfaces = false) {
if (FoundTypes != null && FoundTypes.TryGetValue(interfaceType, out var ft))
return ft;
else {
if (LoadableTypes == null)
RefreshLoadableTypes();
var ans = LoadableTypes
.Where(aType => (includeAbstractClasses || !aType.IsAbstract) &&
(includeInterfaces ? aType != interfaceType : !aType.IsInterface) &&
(includeStructs || !aType.IsValueType) &&
(includeSystemTypes || !aType.IsBuiltin()) &&
interfaceType.IsAssignableFrom(aType) &&
aType.GetInterfaces().Contains(interfaceType))
.ToHashSet();
FoundTypes[interfaceType] = ans;
return ans;
}
}
}
public static class AssemblyExt {
//https://stackoverflow.com/a/29379834/2557128
public static IEnumerable<Type> GetLoadableTypes(this Assembly assembly) {
if (assembly == null)
throw new ArgumentNullException("assembly");
try {
return assembly.GetTypes();
}
catch (ReflectionTypeLoadException e) {
return e.Types.Where(t => t != null);
}
}
}
Note: If you create types at runtime, you will need to run RefreshLoadableTypes to ensure they get returned.
If you are concerned about IBotCommand implementors existing without the CommandAttribute, you can filter the ImplementingTypes, otherwise:
var botCommands = typeof(IBotCommand)
.ImplementingTypes()
.Select(t => new { Type = t, attrib = t.GetTypeInfo().GetCustomAttribute<CommandAttribute>(false) })
.Select(ta => new {
ta.Type,
TriggerString = ta.attrib.TriggerString
})
.ToDictionary(tct => tct.TriggerString, tct => tct.Type);
With an extension method for your command Types:
public static class CmdTypeExt {
public static Task ExecuteAction(this Type commandType) {
var cmdObj = (IBotCommand)Activator.CreateInstance(commandType);
return cmdObj.ExecuteAction();
}
}
You can use the Dictionary like:
var cmdString = Console.ReadLine();
if (botCommands.TryGetValue(cmdString, out var cmdType))
await cmdType.ExecuteAction();
Overall, I might suggest having a method attribute and having static methods in static classes for commands, so multiple (related?) commands can be bundled in a single class.
PS My command interpreters have help associates with each command, and categories to group commands, so perhaps some more attribute parameters and/or another IBotCommand method to return a help string.
Is there a way to do this:
var methodToDoStuffTo = typeof (FancyClass).GetMethod("MethodName").Name;
Without relaying on the string "MethodName"?
What I want is something like this:
var methodToDoStuffTo = typeof (FancyClass).GetMethod(FancyClass.MethodName).Name;
So I can be sure that there is no unexpected error when I rename my method MethodName.
For reasons I can't simple update my enviroment to c# 6, so no nameof().
I try and give a reason why I'am doing this:
I (have to) use one Authorization Attribute on several different Methods.
Depending on from which method the Attribute was 'called', the code has to do slitly different stuff.
That's why I can't / don't want to use differnet Attributes for each Method.
Depending on from which method the Attribute was 'called', the code has to do slitly different stuff
You should never do that. Letting magic stuff happen based on naming conventions is in most application code a bad idea that will lead to unexpected side-effects.
Just add a constructor parameter to the attribute:
public class YourAttribute : Attribute
{
private bool doSomethingDifferent;
public YourAttribute(bool doSomethingDifferent = false)
{
_doSomethingDifferent = doSomethingDifferent;
}
}
And apply it as such:
public class AttributeApplication
{
[YourAttribute]
public void NormalMethod()
{
}
[YourAttribute(doSomethingDifferent: true)]
public void MethodSomewhatDifferent()
{
}
}
But if you really want a type-safe GetMethod(), you could create an extension method with a MethodCallExpression, as explained in Get the name of a method using an expression.
The syntax will then become something like this:
var methodToDoStuffTo = typeof(FancyClass).GetMethod(c => c.MethodName()).Name;
But again, that approach should not be chosen lightly.
Please feel free to modify the title, I couldn't come up with any better one =\
Given the following example class
public class Person
{
public string Name;
public int ID;
public string City;
}
I need to create another mirror class, where every field is actually a wrapper of the original class:
public class PersonMirror
{
public FieldWrapper<string> Name;
public FieldWrapper<int> ID;
public FieldWrapper<string> City;
}
public class FieldWrapper<T>
{
public T Value;
public bool someBool;
public int someCounter;
// ..whatever
}
The thing is, I have many classes to mirror, and some of them have many fields! Moreover, the original class may be changed from time to time (add / remove / rename field), and every change must be applied to the mirrored class - not a good practice for maintainability.
My question is - is there a type safe way automate the decleration (rather then creation, such as generated code) of such mirrored classes?
EDIT:
Let's start from the beginning. In our SOA system, there is a resource access service (serviceX) responsible for updating items in the DB. Other services send it the modifications they would like to perform - in json that would be something like: {ID: 123, name : "myNewName"}. serviceX would then build an update query to send to the DB. However, there is a requirement that serviceX will expose a POCO interface, so that the interface will be language independent, so expressions such as (p=> p.name, "MyNewName") are not allowed. Another requirement is type safety, so json is not allowed either. Currently, the above solution is the best one we came up to answer all the requirements. Any better solutions are more then welcome!
IMO, there's no way to do what you want, except code generation.
Approaches for code generation could differ (this maybe source code generation + compilation, emitting IL code, either your own or existing one), but this is the only way.
use T4 to autogenerate your "WrapperClass".
Below, a proposition of how you could implement your FieldWrapper.
public class FieldWrapper<T, O>
{
private T _item;
private O _owner;
private PropertyInfo _setter;
public T Value
{
get { return _item; }
set {
if (!EqualityComparer<T>.Default.Equal(_item, value))
{
_item = value;
// do some personal check
_setter.SetValue(_owner, value);
}
}
}
public bool someBool;
public int someCounter;
// ..whatever
// CTOR
public FieldWrapper(O owner, Expression<Func<T, O>> propertyExpressionInTheOwner)
{
_owner = owner;
propertyName = (propertyExpressionInTheOwner.body as MemberExpression).Member.Name;
// get PropertyInfo using the owner and propertyName
}
}
Using the expression behavior permits you to create your fieldWrapper this way.
var p = new Person();
new FieldWrapper(p, (pers) => pers.Name);
The good point with this technique it is that if you person class change you will directly receive a compilation error.
With T4 the must is to load the assembly where all you class are, tag you class model with a specific attribute. Look into the assembly to found every class that have this attribute and generate the wrapper class associate.
You would have to run it after every code change, but you could create a code parsing application.
List desired keywords to substitute, such as " string ", " int ". Read the file, line by line. Find definition of classes (line contains "class"), then replace every instance of any given keyword in it with:
"FieldWrapper<" + keyword + ">"
You might want to drop keyword substitution inside methods (and perhaps in the method signatures / return types themselves) of by checking for "(" and ")", and the opening curly brace. Resume operation when you reach the closing curly brace. You can achieve that by storing the nesting level in an integer, incrementing it when hitting '{' and decrementing it when reaching '}'.
I am working on an application where a form will be created at runtime based on data from a database. It currently uses reflection to create the control and add it to the form.
With this I can easily dynamic create a form at runtime, but next I ran into the issue of how to access the currently selected, eg: TextBox.Text versus DropDownList.SelectedValue. To "fix" this, I created an interface with the method of GetValue. With this, I create a new class and inherit from the respective control and implement the interface.
Now I can easily iterate over the form controls to see if they implement the interface and then get the value of the control.
The question to all of this is: Is this the best way to accomplish this?
To note: I fully expect the controls available to build these forms to get to 15+.
Example of class:
public interface IFormField
{
string GetId();
object GetValue();
}
public TextBox : System.Web.UI.WebControls.TextBox, IFormField
{
public string GetId()
{
return ID;
}
public object GetValue()
{
return Text;
}
}
While I like interfaces, as noted with the "create a new class and inherit from the respective control" .. using new interfaces require that the underlying types are modified. This is not always practical for this case. So, while I won't claim that interfaces aren't appropriate here, I will provide alternative ideas.
This first approach uses a companion object which knows about the control, and how to get the value from the control. This class could use an interface but it is not required here. It allows delaying of the fetcher (in a well-typed manner) but also requires that it's explicit set per companion instance.
interface IWithValue {
string Value { get; }
}
class ControlCompanion<T>: IWithValue where T: Control {
IFunc<Control, string> readValue;
public T Control { get; private set; }
public string Value { get { return readValue(Control); } }
public ControlCompanion (T control, IFunc<T, string> readValue) {
Control = control;
this.readValue = readValue;
}
}
// this is typed narrowly here, but it could be typed wider to
// the actual ControlCompanion if needing additional information
// or actions wrt. the particular control
var valueAccessors = new List<IWithValue>();
var textBox = new TextBox();
valueAccessors.Add(new ControlCompanion(textBox, (c) => c.Text));
var comboBox = new ComboBox();
valueAccessors.Add(new ControlCompanion(comboBox, (c) => c.SelectedValue));
var allValues = valueAccessors.Select(v => v.Value);
Another alternative is to create a function that knows how to extract the values. Because these controls are "created dynamically" (e.g. of type Control) we can't use method overloading directly and must therefore accept the more general type and use some form of reflection or type refinement.
string GetValue(Control c) {
// using this form will allow invalid path detection
TextBox tb;
ComboBox cb;
if ((tb = c as TextBox) != null) {
return tb.Text;
} else if ((cb = c as ComboBox) != null) {
return GetValue(cb);
} else {
throw new Exception("Unsupported control");
}
}
// but we could use overloading once refined ..
string GetValue(ComboBox cb) {
return cb.SelectedValue;
}
Of course, the above two approaches could be combined1 - e.g. a GetValue function that use a per-type extractor (similar to ControlCompanion but independent of a control instance) looked up by a map/dictionary based on the actual type of the control object. If one didn't even want to maintain the map/dictionary manually, assembly reflection could load these per-type extractors automatically - oh, the possibilities and possible complexity!
Along the same lines but more general than the above suggestion is to use Type Converters which is quite a complete (if not complex) setup to handle converting types - even when those types cannot be modified or extended.
There are several different possibilities, and while extending controls and adding interfaces does usually work (it requires the controls can be registered as safe and created by the particular refined implementation), it is limited to cases in which said types can accommodate such changes.
1Okay, here is a rough idea for a general "switchless" GetValue. Note that it separates the control instance from the "fetcher". In fact, such an inversion could even be used to "get companions" to avoid explicit wrapping as in the first example.
interface IFetchValue {
string FetchValue(Control c);
}
abstract class Fetcher<T>: IFetchValue where T : Control {
abstract protected FetchControlValue(T c);
public string FetchValue (Control c) {
return FetchControlValue((T)c);
}
}
class TextBoxFetcher: Fetcher<TextBox> {
protected string FetchControlValue (TextBox tb) {
return tb.Value;
}
}
class ComboBoxFetcher: Fetcher<ComboBox> {
protected string FetchControlValue (ComboBox cb) {
return cb.SelectedValue;
}
}
// This could be initialized via reflection of all
// Fetcher<T>/IFetchValue types with a bit more work.
IDictionary<Type, IFetchValue> map = new Dictionary<Type, IFetchValue> {
{ typeof(TextBox), new TextBoxFetcher() },
{ typeof(ComboBox), new ComboBoxFetcher() },
};
string GetValue(Control c) {
IFetchValue fetcher;
// This should be smarter to also try parent types or
// check general assignability.
if (c != null && map.TryGetValue(c.GetType(), out fetcher)) {
return fetcher(c);
} else {
throw new Exception("Whoops!");
}
}
In addition, your favorite DI/IoC framework might support similar resolve capabilities which would then just push this maintenance into the configuration. Again - many ways, and many ways to make it complicated.
Pretty much. This is one of the main reasons why inheritance/polymorphism are useful. It allows calling code to deal with a generic collection which could actually have many deriving types and deal with them all as if they were the same thing.
If you only have a two or three types it might be simpler to skip this, but as the set of types you can operate on grows this rapidly becomes the best option. Also, I'd like to point out that I don't deal with WinForm types very much, there may already be some support for this type of behavior (which you'd be duplicating) that I don't know about.
You can do it this way (just to state the obvious...), but personally I wouldn't have. Extending a number of controls when all you are doing is adding a single method as part of an interface implementation is a reasonably long winded way to do it.
I would have used a helper method which takes a Control as its input, and checks the type of the control (via casting in lieu of a more language specific option) and then returns the control's value as an object.
The purpose of an interface is to establish a contract irrespective of the actual implementation, so you haven't used it incorrectly, you've just done more work than you really needed to.
Your approach is good and correct if it fullfils your needs and simplifies life.
I want to show an alternative way of control's value retrieval, the way of how it is accomplished in ASP.NET Web Forms itself. This approach could be useful if you don't want to bother with inheritance and if you are using standard input controls or all your controls are decorated with ValidationPropertyAttribute (which is mandatory if you want to use standard validation controls with your custom ones).
To retrieve value of any standard input control we need to use BaseValidator.GetValidationProperty method. This method returns PropertyDescriptor instance for validation property which holds control's value (except ListItem, but this case is covered in code snippet).
So the complete code for value retrieval would be:
public static string GetControlValue(Control c)
{
// This code is copied as-is from BaseValidator.GetControlValidationValue method
PropertyDescriptor prop = BaseValidator.GetValidationProperty(c);
if (prop == null) {
return null;
}
object value = prop.GetValue(c);
if (value is ListItem) {
return((ListItem) value).Value;
}
else if (value != null) {
return value.ToString();
}
else {
return string.Empty;
}
}
In the code base I was maintaining I found this exact class, pasted below. In logPath property, gets does some work. I would think that it is better to do the work in set - that way it will be done only once. However, partly because this is how the class is written, partly because it is an xml-mapped property, and partly because I am afraid that I might miss something in a debugger, I have doubts.
Additionally, if an element never existed in the xml, and it happened to be optional, then I think I will get a null for the value. I might actually want to differentiate between having no element and receiving empty value. I suppose I can have a private bool member which can help me detect that - that would be an argument for doing work in set rather than get. So, code optimizers work hard these days, so performance is rarely a true concern. It is more of a "figure this out once and do not think about it later" things. This is just one example, and properties frequently do some massaging.
Would you say that it is always better to do work in set? In get? It depends? A mixed style would not bother you a single bit as long as it works?
Thanks.
namespace MyNamespace
{
using System;
using System.Xml.Serialization;
/// <summary>
/// The LoggingListener class encapsulates the "logListener"
/// element of config file, and puts the "logPath"
/// attribute in a file path string.
/// </summary>
public class LoggingListener
{
private string logPathValue;
/// <summary>
/// Gets or sets the LOCAL file path to a log file
/// which will be written during operation of the Updater.
/// </summary>
[XmlAttribute("logPath")]
public string LogPath
{
get
{
return this.logPathValue == null ?
String.Empty : this.logPathValue;
}
set
{
this.logPathValue = value;
}
}
}
}
EDIT: In this given sample ... if the log file is not there, then no logging should take place.
I'd certainly prefer consistency. But the fact is in cases like this it often will not matter. I'm sure the original developer's intent was to avoid the infuriating NullReferenceException bug resulting from attempting to access the LogPath property of some LoggingListener object -- in which case, it probably just seemed most sensible to put the null check in the get (since that's where the exception was thrown).
In general, I'd agree with you that perhaps it makes the most sense to put it in the set -- but then, there's no guaranteeing LogPath will never return null, as the private member could have been set to null from within the class, or perhaps it was never set at all (as Kevin pointed out).
I tend to go with a somewhat hybrid approach: make the property read-only, and make sure it gets set to something non-null in the constructor:
public class LoggingListener {
private readonly string _logPath;
public LoggingListener(string logPath) {
_logPath = logPath ?? string.Empty;
}
public string LogPath {
get { return _logPath; }
}
}
Whether this is an acceptable compromise obviously depends on your specific needs. Also, whether the property should really never be null after all is certainly debatable, depending on the scenario, as you've already remarked.
I personally don't like when property changes assigned value in either get or set accessor. It changes expected property behavior:
var value = null;
var listener = new LoggingListener();
listener.LogPath = value;
if(listener.LogPath != value)
{
// how could we get here?
}
Instead, I prefer to clearly decide, whether property can accept null or not. If it can, it shouldn't do any work in get/set, if yes, it should neither return null nor accept it as a value.
If there is no way to prevent assignment of null, than i would prefer to handle this case in set accessor.
With getters and setters I follow a few rules:
No side effects - don't modify 'B' when you put a value in 'A'
What I put in 'A' comes out of 'A', if you need to modify 'A' expose a new read-only property
If you don't like my value for 'A', tell me now not later when I call a method
Outside of a data model, do not accept or return null
For your example I prefer seeing the following:
public class LoggingListener
{
private string logPathValue = String.Empty;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set
{
if(value == null) throw new ArgumentNullException();
this.logPathValue = value;
}
}
}
Yet it's clear to me why you ask, it really about the behavior of "XmlAttribute" and the XmlSerializer. You can use the "DefaultValueAttribute" from the ComponentModel namespace, or use an XSD to provide the defaults, or expose a new property and/or method. You could also try creating an interface to separate concerns, something like the following:
public class LoggingListener : ILogListenerSettings
{
private string logPathValue;
[XmlAttribute("logPath")]
public string LogPath
{
get { return logPathValue; }
set { logPathValue = value; }
}
string ILogListenerSettings.FullLogPath
{
get
{
string path = logPathValue;
if(String.IsNullOrEmpty(path))
path = Environment.CurrentDirectory;
path = Path.GetFullPath(path);
Directory.Create(path);
return path;
}
}
}
the only way to be sure that logPathValue is initialized is to do it yourself...
public class LoggingListener
{
private string logPathValue = string.Empty;