I have a method which searches for employees. This method got a lot of optional parameters as search-parameters. My Api is used in many single programs in our system and i want to add two new optional parameter to it. If iam doing so compiler is fine, but the using programs of my api are getting Method missing exceptions. Ok i understand that so far, because intern the old Method isnt longer existing (parameterlist is different). Now i thought i easily can overload it. But now the compiler can't different my two methods (old and overload) for sure.
Small example:
Old-Version:
public virtual List<IEmployee> Search(int? personalNr = null, bool? active = null, DateTime? dateOfBirth = null)
Needed-Version:
public virtual List<IEmployee> Search(int? personalNr = null, bool? active = null, DateTime? dateOfBirth = null, string firstName = null, string lastName = null)
Just want to add two parameters. I know i can compile all using dll, but this API is used massive and i don't want to transfer all dll's on Live-System.
Is there a common way how to handle this situation?
CLARIFY
1.
I just add two new optional parameters to the existing method to extend it:
All calling programs getting Missing-Method Exception because the signature changed.
2.
I overload the method. Now the compiler can't differ the overload and the method. This i quite clear to me. Someone could call Search(active: true); which method should .Net take?
From my point of view the best way to do it is :
declare a private method that need all the parameters and which manage the emptyness (or not) of each parameters.
declare one public method for each number of parameters possible
each public method call the private method converting missing parameters to empty parameters.
From my point of view i don't think using optionnal paremeters is a good idea
Hey thank you guys for response. My problem is that i don't want to effect the programs outside. So i decided to create a new class SearchParams. This holds all parameters listed. So i can overload my existing method and pass SearchParams as parameter. I will set old method Obsolete. The SearchParams class is free extendable then.
Changes:
Create new class like this:
public class SearchParams
{
public int? PersonalNr{get;set;}
public bool? Active {get;set;}
public DateTime? DateOfBirth{get;set}
public string FirstName{get;set;}
public string LastName{get;set;}
}
Overload Search-Method:
public List<IEmployee> Search(SearchParams paramList)
So the caller first creates the parameter and pass this to the search.
In my opinion this seems to be the best way.
This is another suggestion.
You can remove optional parameters from the old method. Make all parameters mandatory.
public virtual List<object> Search(int? personalNr, bool? active, DateTime? dateOfBirth)
{
}
Then make all parameters optional in your second method.
public virtual List<object> Search(int? personalNr = null, bool? active = null, DateTime? dateOfBirth = null, string firstName = null, string lastName = null)
{
}
Now suppose you are calling this method like this;
Search(1,true, DateTime.Now);
The above will execute your old method.
Search(1,true, DateTime.Now, null);
This will execute your new method.
However, if I was in your position, I would have just renamed the old method.
The problem may come from the position of your optional parameters.
It seems that it is compiling "for some reason" but that should not be working.
As a workaround, you should modify your needed version :
public virtual List<IEmployee> Search(int? personalNr = null, bool? active = null, DateTime? dateOfBirth, string firstName = null, string lastName = null)
Leave the old method as well but move the code from your "basic" version to the overloaded one. And when the "basic" search is called, just call your search method and fit the firstName and the lastName as null parameters.
EDIT: Just saw your edit, my post does not make much sense then :)
Related
I have a 'Validator' class that needs to do some simple validation. However, there are some instances where all or just a single method may need to be called.
The interface for the validator is defined as:
internal interface IBrandValidator
{
BrandInfo ValidateBrands();
}
The class definition for the object being returned:
internal class BrandInfo
{
public Organisation Brand { get; set; }
public Client Client { get; set; }
public Location Location { get; set; }
public Language Language { get; set; }
}
The class that implements this interface:
internal class ClientValidator : IBrandValidator
{
private readonly int? clientId;
private readonly int? locationId;
private readonly int? languageId;
public ClientValidator(int clientId, int? locationId, int? languageId)
{
this.clientId = clientId;
this.locationId = locationId;
this.languageId = languageId;
}
public BrandInfo ValidateBrandDimensions()
{
var brandInfo= new BrandInfo();
//Optional validation
if(client != null)
brandDimensions.Client = ValidateClient(clientId);
if(locationId != null)
brandDimensions.Location = ValidateLocation(locationId);
if(languageId != null)
brandDimensions.Language = ValidateLanguage(languageId);
return brandInfo;
}
}
My question is. The 3 validation methods under the comment 'Optional Validation'. May or may not need to be called. However, there may be additional things I need to validate in future and using the nullable int with the if statement is a bad route.
Is there a design pattern I can implement to achieve something similar?
Your code is hardly predictable by reading for example:
brandDimensions.Client = ValidateClient(clientId);
ValidateClient should return truthy or falsy object. But is assigned to an Object with name "Client".
Your validator returns an BrandInfo Object. But does not include any property or method which indicates if it is valid or not ?!?
The ClientValidator does not have to validate for a client - because it is nullable?
It think you should consider to reorganize part of your codes.
If a class creates many objects from an Identifier you could probably use the Factory Pattern.
If you want to validate a complex object name it after ComplexObjectValidator.
Every part of the complex object gets validated.
If it is valid that for example an Id is nullable put that check in the Validator Implementation.
It is hard to tell more specifics because it is unclear what your code does or intends to do.
Edit:
As rule of thumb:
Truthy or falsy Methods: Prefix with "Is" "Must" "Should" "Has" "Can" etc.
If a method should return an Object: "GetValidatedClient" "ValidateAndReturnClient" "CreateClient"
So someone reading your code which can be you in the future (6 months, 3 years, 10 years) can just infer the behaviour from your function names.
ValidateClient would imply that it is just Validating. More specifically it just returns void. Because it just Validates. If it returns truthy or falsy values use one of the prefixes listed above. If it returns an Validator Object use "GetValidationResultFor(xyz)" for example.
First of all, apologies if I posted it in the wrong place, I'm new here and I'm not sure if I posted in the right place.
Well, I'm trying to build a generic search method, where I'll add search parameters to mount a SQL Query and execute it on the database. All that using C#. My goal is that the parameter corresponding to the field I'll search, to be a property of the class the method is in. For example:
public foo
{
public string CustomerCode { get; set; }
public string CustomerName { get; set; }
public void AddSearchParameter(???, EnumOperator Operator, object Value)
}
Whenever I want to specify a parameter to add on the search, I would like it to look like this:
foo xxx = new foo();
xxx.AddSearchParameter(foo.CustomerCode, EnumOperator.Equal, txtCustomerCode.text);
My question is how to do it?
If you are trying to pass the member information (so that the AddSearchParameter can inspect the MemberInfo and write suitable SQL), then you'd need to use either a string literal (i.e. "CustomerCode"), or an expression tree. The latter is richer, but involves learning the Expression<T> API. But fundamentally:
public void AddSearchParameter(Expression<Func<object>> expression, ...)
...
xxx.AddSearchParameter(() => foo.CustomerCode, ...)
This, however, is not a trivial area of .NET.
If I were doing something like this, I would probably make the Search() method on foo check for the existence of values in the various this properties, and then build the query based on that.
public List<Results> Search()
{
if (!String.IsNullOrEmpty(this.CustomerCode))
{
// add search value to query
}
// etc.
}
This seems like a simple question, but for some reason I can't find the answer anywhere. Basically, I'd like to be able to implement a constructor that takes NamedParameters.
By named parameters, I do not mean parameters with default values (optional parameters) such as:
public SomeMethod(){
string newBar = Foo(bar2 : "customBar2");
}
public string Foo(string bar1 = "bar1", bar2 = "bar2" ){
//...
}
A good example of what I'm trying to achieve is the AuthorizeAttribute from the System.Web.Mvc assembly. Which you can use the following way:
[Authorize(Roles = "Administrators", Users = "ThatCoolGuy")]
public ActionResult Admin(){
}
The constructor's signature in intellisense looks like the following example and I believe (please confirm) that those NamedParameters are mapping to class properties.
AuthorizeAttribute.AuthorizeAttribute(NamedParameters...)
Initiliaze new instance of the System.Web.Mvc.AuthorizeAttribute class
Named parameters:
Order int
Users string
Roles string
Please note:
The syntax of defining the parameter name when calling a method has nothing to do with optional parameters:
You can use Foo(bar1 : "customBar1"); even if Foo is declared like this: void Foo(string bar1)
To answer the question:
My guess is that this is syntactic sugar similar to the object initializers introduced in Visual Studio 2010 and therefore you can't use this for your own classes.
The behaviour you are talking about is specific for attributes and cannot be reused in "normal" classes constructors.
You don't need to "implement" anything.
The parameters can be used in the manner you describe just by existing as parameters on the constructor.
You do need to be using C# 3.5 or above, when they were introduced.
Your example will compile and run on C# 4.0 / Visual Studio 2010 without modification.
See Named and Optional Arguments (C# Programming Guide) on MSDN.
In regards to properties on the object, that do not have a corresponding constructor arguments, the exact syntax is specific to attributes and can't be replicated, though, with object initializers you can get close.
You can use the builder/constructor info pattern together with property initializers.
class PersonInfo
{
public string Name { get; set; }
public int? Age { get; set; }
public Color? FavoriteColor { get; set; }
public Person BuildPerson()
{
return new Person(this);
}
}
class Person
{
public Person(PersonInfo info)
{
// use info and handle optional/nullable parameters to initialize person
}
...
}
var p = new Person(new PersonInfo { Name = "Peter", Age = 15 });
// yet better
var p = new PersonInfo { Name = "Peter", Age = 15 }.BuildPerson();
I however don't understand, why you don't just use named parameters and provide null for indicating optional parameters.
class Person
{
public Person(string name = null, int? age = null, Color? favoriteColor = null) { /* ... */ }
}
var p = new Person(name: "Peter", age: 15);
Named parameters are NOT specific to attributes. It's a language syntax that can be used everywhere. It's fine to use properties for initialisers but you don't always want to have internals set as set properties.
Just instantiate you class using:
TheClass c = new Theclass(param3:firstValue, param1:secondValue, param2:secondValue);
With regards to this part of the question:
"I however don't understand, why you don't just use named parameters and provide null for indicating optional parameters."
The reason named parameters are nice is you don't need to provide extraneous values in parentheses, just what you want to specify, because if it's optional you shouldn't even need to put null. Furthermore, if you specify null, you are overriding any default value for that parameter which makes it optional. Being optional implies there's a default value meaning nothing passed in.
Property initialisation at instance time is purely there for convenience. Since C there has been the ability to initialise values at construction time on types. Which is handy if those values can't be specified in the constructor. I personally feel that the convenience of them has spoiled people and it get a little too liberal and make everything public get AND set. Just depends on the design and security of properties you need.
I doubt that's possible. This is something specific for attributes.
I think the closest option is to use an object initializer:
class Foo {
public string Name {get;set;}
public int Data {get;set;}
}
var foo = new Foo {Name = "MyName", Data = 12};
try to use this signature
[AttributeUsage(AttributeTargets.Class)]
before the name of your class
Please refer to MSDN specification for full description:
https://msdn.microsoft.com/en-us/library/aa664614(v=vs.71).aspx
"Each non-static public read-write field and property for an attribute class defines a named parameter for the attribute class".
Visual C# 2010 introduces named and optional arguments. Named argument able you to specify an argument for a particular parameter by associating the argument with the parameter's name rather than with the parameter's position in the parameter list.Named arguments free you from the need to remember or to look up the order of parameters in the parameter lists of called methods.
static void Main(string[] args)
{
mapingFunction(snum2: "www.stackoverflow.com", num1: 1);
}
public static void mapingFunction(int num1, string snum2)
{
Console.WriteLine(num1 + " and " + snum2);
}
here you can see that argument are passed with our their order
What you probably want to do is implement public properties in your attribute:
public class AuditFilterAttribute : ActionFilterAttribute
{
public string Message { get; set; }
public AuditFilterAttribute() { }
}
They can be accessed through Named Parameters where you apply it:
[AuditFilter(Message = "Deleting user")]
public ActionResult DeleteUser(int userId)
Hope that helps...
C# 4 introduced a feature called named arguments which is especially useful in scenarios like
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
Is there a way to force using named arguments? Maybe some attribute to apply to a method or a compiler switch I'm not aware of? I guess it can be done with code inspector tools but just want to know if there is other way.
p.s.
For those interested why one may need it and why not just use a class/struct to utilize object initializers there are scenarios when it's impossible. Like calls to libraries not in your control or weird code conventions you have to obey.
It's possible to force the callers to always use named args. I wouldn't do this in most circumstances because it's rather ugly, but it depends on how badly safe method usage is needed.
Here is the solution:
int RegisterUser(
#if DEBUG
int _ = 0,
#endif
string nameFirst = null,
string nameLast = null,
string nameMiddle = null,
string email = null) { /*...*/ }
The first parameter is a dummy that shouldn't be used (and is compiled away in Release for efficiency). However, it ensures that all following parameters have to be named.
Valid usage is any combination of the named parameters:
RegisterUser();
RegisterUser(nameFirst: "Joe");
RegisterUser(nameFirst: "Joe", nameLast: "Smith");
RegisterUser(email: "joe.smith#example.com");
When attempting to use positional parameters, the code won't compile.
No, not in the C# language. It will always accept positional parameters if all the parameters are supplied.
You could build a custom FxCop rule or an StyleCop rule to enforce this - as pointed out in the comments, it is likely a StyleCop rule you would be interested in (thanks to Kris).
Sorry for a shameless plug!
I implemented a Roslyn analyzer to enforce using named arguments for a method.
So if you install the RequireNamedArgs analyzer and add a special comment before a method that should be invoked with named arguments:
//[RequireNamedArgs]
int RegisterUser(string nameFirst, string nameLast, string nameMiddle, string email)
The analyzer will emit an error if a caller attempts to use positional arguments instead of named.
Take a look at it in action:
If you decide to give it a go -- do so at your own risk :)
I've also sought a way to force named arguments. Optional parameters can be dangerous, especially if you have multiple parameters of the same type. Overloads are almost always a safer solution, but there are times when you have a method that can take many combination of arguments, so creating 20 overloads to account for ever possibility is overkill.
In extreme situations where it is of the utmost importance that arguments be named at all times, I will create an argument class with no defined constructor. In your case, you could do this:
public class UserRegistrationArguments
{
public string nameFirst { get; set; }
public string nameLast { get; set; }
public string nameMiddle { get; set; }
public string email { get; set; }
}
Call it like this:
RegisterUser(new UserRegistrationArguments { nameFirst = "Bob", nameLast = "Slob" });
You could also simplify it like this:
public class UserRegistrationArguments
{
public string nameMiddle { get; set; }
public string email { get; set; }
}
int RegisterUser(string nameFirst, string nameLast, UserRegistrationArguments args = null)
...and do this:
RegisterUser("Bob", "Slob", new UserRegistrationArguments { nameMiddle = "Teh" });
This way, you only have one optional parameter and that's for your optional parameters.
Edit: Maybe I didn't read the OP correctly. You're not using optional arguments? If not then this answer probably doesn't help you.
I'm using another method. In my setup I have 1 parameter which I always expect, then come a bunch of optional strings which I really want to be sure the user chose actively. So my first string in this list is a "trap" value, which if set, throws an error. Like this:
public HtmlString Toolbar(DynamicEntity target = null, string dontRelyOnParameterOrder = Constants.RandomProtectionParameter, string actions = null, string contentType = null, object prefill = null)
{
if (!Enabled) return null;
protectAgainstMissingParameterNames(dontRelyOnParameterOrder);
var toolbar = new ItemToolbar(target, actions, contentType, prefill);
return new HtmlString(toolbar.Toolbar);
}
private void protectAgainstMissingParameterNames(string criticalParameter)
{
if(criticalParameter != Constants.RandomProtectionParameter)
throw new Exception("when using the toolbar command, please use named parameters - otherwise you are relying on the parameter order staying the same.");
}
Hope you like it :)
I have a class that in order to do it's job needs to have 8 different property values set.
I want to make sure that all 8 properties are set before trying to execute a method.
I currently have all the parameters passed in and set via the constructor.
Is there a better way to do this?
You can allow the object to be created without specifying values for all the properties and then the method would throw an InvalidOperationException if called before the object state is valid for the method call to execute, which in this case would mean that all 8 properties would have valid values.
This way you give more flexibility to the consumer. It can create a new instance at one moment, set it's properties at another and only then call the method. This is a "pattern" that is used through the .NET codebase and to which developers are already used.
Update:
This also simplifies things if you're adding other methods that don't need the full set of properties to be initialized. Yes we could add another constructor overload with the new set of properties, but what if we have 2 methods that both need one property of the same type to be initialized? This is not solvable by using constructor overloads.
In my opinion if a class requires these 8 objects in order to function then they should be passed into the constructor and by no other means. I'm a big fan of dependency injection anyway, but this method also allows for better unit testing by passing in mocked objects and such.
you could consolidate the parameters into a Parameter Object and just pass that instead.
If you were using this class from XAML you would make all 8 properties individually settable and throw an exception if somebody tries to execute a method without them all set. It's also possible that you would want to "freeze" the object once a method was called and throw an exception if somebody tries to set a property on a "frozen" object.
I'm not going to pass judgement on which method is better, though.
A constructor is the only way to do it at compile time. The other option would be to throw an exception if not all the parameters have been set.
Give them default values?
Maybe you can give a bit more of the context to let us help you!
Use setter in the properties. When property is used by the method and it is not set already, setter would do it for you. This is not the recommended approach thogh but might be needed in some situations.
Some thing similar would work
Class SomeClass
{
string name;
string Name
{
set
{
if (name == null)
name = value;
}
}
}
The constructor sounds like the best way to do this since it will be verified at compile tile. Of course, you could have default values for some or all of the properties and then chain constructors, so that not every property needs to be set in the constructor. Something like:
public class Person
{
public string Name { get; set; }
public double Height { get; set; }
public DateTime DoB { get; set; }
public Person(string name, double height, DateTime dob) : this(name, height)
{
this.DoB = dob;
}
public Person(string name, double height)
{
this.Name = name;
this.Height = height;
this.DoB = DateTime.Now.Date;
}
}
This means you can construct a new Person object using either two or three parameters, but all will be set (but if you use two then DOB will get a default of today):
Person person1 = new Person("Geoff", 1.8, new DateTime(1950, 5, 12));
Person person2 = new Person("John", 1.54); // Gets default DOB
You can use an object initializer if you are using c# 3.0 onwards. This is arbitrary whether it's 'better' or not.