20

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
Kiquenet
  • 14,494
  • 35
  • 148
  • 243
Pierluc SS
  • 3,138
  • 7
  • 31
  • 44
  • @Jodrell If you look at class definition in metadata or reflector, there is only 1 constructor definitions of AuthorizeAttribute which takes no parameters, but somehow you can pass it class properties (named parameters) – Pierluc SS Aug 21 '12 at 14:10

10 Answers10

19

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.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
  • It seems that [named arguments](https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/named-and-optional-arguments#named-arguments) can be used in 2021 for own classes: `MyClass foo = new MyClass(id:1,qty:4)` – surfmuggle Feb 07 '21 at 12:24
  • @surfmuggle: Exactly. But that always was the case, as you can see in this answer from 2012 you commented on :) – Daniel Hilgarth Feb 09 '21 at 19:11
17

The behaviour you are talking about is specific for attributes and cannot be reused in "normal" classes constructors.

mathieu
  • 30,974
  • 4
  • 64
  • 90
  • 3
    Names parameters have been around since .NET 4.0 - they are not for attributes only. – Oded Aug 21 '12 at 14:11
  • 1
    OP wants the same behavior as in attributes : using class properties as optional parameters – mathieu Aug 21 '12 at 14:14
  • 3
    @Oded: Please note the difference between `Name = "Value"` and `name: "Value"`. This tiny difference is what the OP wants. This answer doesn't deserve the downvotes. – Daniel Hilgarth Aug 21 '12 at 14:15
  • 7
    As soon as any class have the **Attribute** class in their inheritance tree, if that class has a property with a public set, it will appear in intellisense definition and will be useable as a **NamedParameter** – Pierluc SS Aug 21 '12 at 14:21
8

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.

Oded
  • 489,969
  • 99
  • 883
  • 1,009
  • 1
    "By named parameters, I do not mean parameters with default values (optional parameters) such as" + "The constructor's signature in intellisense looks like the following example and I believe (please confirm) that those NamedParameters are mapping to class properties." – mathieu Aug 21 '12 at 14:15
  • 1
    That's not entirely true. Named parameters are possible within a .NET 3.5 application, but you need VS2010. – Jensen Aug 21 '12 at 14:16
4

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);
Sebastian Graf
  • 3,602
  • 3
  • 27
  • 38
  • Ok... `new Person(name: "Peter", age: 15);` doesn't look that worse to me compared with something like `new Person { Name = "Peter", Age = 15 }`. I think it's just that one isn't used to see colons in method parameters... – Sebastian Graf Aug 21 '12 at 14:21
3

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.

Tshilidzi Mudau
  • 7,373
  • 6
  • 36
  • 49
Stephen York
  • 1,247
  • 1
  • 13
  • 42
2

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};
Jensen
  • 3,498
  • 2
  • 26
  • 43
1

try to use this signature

[AttributeUsage(AttributeTargets.Class)]

before the name of your class

Irvin Dominin
  • 30,819
  • 9
  • 77
  • 111
1

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

Tshilidzi Mudau
  • 7,373
  • 6
  • 36
  • 49
Adiii
  • 54,482
  • 7
  • 145
  • 148
1

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".

ρяσѕρєя K
  • 132,198
  • 53
  • 198
  • 213
rahnema1
  • 15,264
  • 3
  • 15
  • 27
1

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...

Fred Mauroy
  • 1,219
  • 1
  • 11
  • 10