Làm thế nào bạn có thể sử dụng các tham số tùy chọn trong C #?


493

Lưu ý: Câu hỏi này đã được hỏi tại thời điểm C # chưa hỗ trợ các tham số tùy chọn (tức là trước C # 4).

Chúng tôi đang xây dựng API web được tạo lập trình từ lớp C #. Lớp có phương thức GetFooBar(int a, int b)và API có phương thức GetFooBarlấy tham số truy vấn như thế nào &a=foo &b=bar.

Các lớp cần hỗ trợ các tham số tùy chọn, không được hỗ trợ trong ngôn ngữ C #. Cách tiếp cận tốt nhất là gì?


7
Hoặc chờ đơn vị C # 4.0 được phát hành. Các tham số tùy chọn được hỗ trợ.
Mi-chê

Câu trả lời:


1055

Ngạc nhiên là không ai đề cập đến các tham số tùy chọn C # 4.0 hoạt động như thế này:

public void SomeMethod(int a, int b = 0)
{
   //some code
}

Chỉnh sửa: Tôi biết rằng tại thời điểm câu hỏi được hỏi, C # 4.0 không tồn tại. Nhưng câu hỏi này vẫn được xếp hạng số 1 trong Google về "đối số tùy chọn C #" vì vậy tôi nghĩ - câu trả lời này đáng để ở đây. Lấy làm tiếc.


58
Tại thời điểm câu hỏi được đặt ra, C # 4.0 không tồn tại.
Forrest Marvez

91
Đúng, bỏ qua điều này, xin lỗi. Nhưng câu hỏi này vẫn được xếp hạng số 1 trong Google về "đối số tùy chọn C #" vì vậy dù sao đi nữa - câu trả lời này đáng để ở đây :)
Alex

45
Tốt cho bạn để cung cấp thông tin cập nhật. Lý tưởng nhất là các câu trả lời ban đầu sẽ được cập nhật với thông tin hiện tại như C # 4.0. Tôi tin rằng đó là những gì các chàng trai SO ban đầu có trong đầu, một tâm lý Wiki, nhưng mọi người đều hơi ngại khi chỉnh sửa câu trả lời của người khác.
Rowan

Một điều thú vị mà tôi đã khám phá với WebService là (chắc chắn trong dự án tôi đang thử nghiệm) tất cả các giá trị bool trong chuỗi truy vấn đều là tùy chọn theo mặc định. Rõ ràng họ mặc định là FALSE.
Carlos P

4
Điều đáng chú ý là các tham số tùy chọn phải được đặt sau tất cả các tham số không tùy chọn. tức là bạn không thể có khoảng trống công khai someMethod (int b = 0, int a)
Andrew Meservy

129

Một tùy chọn khác là sử dụng từ khóa params

public void DoSomething(params object[] theObjects)
{
  foreach(object o in theObjects)
  {
    // Something with the Objects…
  }
}

Được gọi như ...

DoSomething(this, that, theOther);

57
Câu trả lời này giải thích từ khóa params beautifilly trong 10 dòng, MSDN vẫn không thực hiện được trong 30. +1
User2400

1
Cảm ơn! Điều này truyền cảm hứng cho tôi để viết một chức năng ghi nhật ký đơn giản (cho trường hợp sử dụng hiện tại của tôi): public void log (params object[] args){ StringBuilder sb = new StringBuilder(); for (int i = 0; i < args.Length; i++){ sb.Append("{"); sb.Append(i.ToString()); sb.Append("}"); sb.Append(" "); } String.Format(sb.ToString(),args).Dump(); }Cuộc gọi mẫu:log("...Done,",(watch.ElapsedMilliseconds/1000).ToString(),"s");
pfonseca

bạn có thể đề cập, net 3.5 có hỗ trợ không? tài liệu chính thức không đề cập đến điều đó.
T.Todua

@ T.Todua - Tôi không chắc chắn 100% những gì bạn đang hỏi ở đây - khung dotnet 3.5 bao gồm C # v3.0 - phiên bản 3.0 đã hỗ trợ từ khóa params, nhưng không có tham số tùy chọn, được giới thiệu trong C # v4.0 , được bao gồm trong khung dotnet 4.0
Tim Jarvis

@TimJarvis vâng, đó là tôi đã yêu cầu. tnx
T.Todua

77

Trong C #, tôi thường sử dụng nhiều dạng của phương thức:

void GetFooBar(int a) { int defaultBValue;  GetFooBar(a, defaultBValue); }
void GetFooBar(int a, int b)
{
 // whatever here
}

CẬP NHẬT: Điều này được đề cập ở trên là cách mà tôi đã làm các giá trị mặc định với C # 2.0. Các dự án tôi đang làm hiện đang sử dụng C # 4.0 hiện hỗ trợ trực tiếp các tham số tùy chọn. Đây là một ví dụ tôi vừa sử dụng trong mã của riêng mình:

public EDIDocument ApplyEDIEnvelop(EDIVanInfo sender, 
                                   EDIVanInfo receiver, 
                                   EDIDocumentInfo info,
                                   EDIDocumentType type 
                                     = new EDIDocumentType(EDIDocTypes.X12_814),
                                   bool Production = false)
{
   // My code is here
}

1
Tôi tin rằng bạn không thể gọi các hàm tạo trong các tham số mặc định, chúng cần tương thích "biên dịch thời gian", không phải là "thời gian chạy" ... Hay tôi sai?
Alex

45

Từ trang web này:

http://www.tek-tips.com/viewthread.cfm?qid=1500861&page=1

C # không cho phép sử dụng thuộc tính [Tùy chọn] (từ VB, mặc dù không hoạt động trong C #). Vì vậy, bạn có thể có một phương pháp như thế này:

using System.Runtime.InteropServices;
public void Foo(int a, int b, [Optional] int c)
{
  ...
}

Trong trình bao bọc API của chúng tôi, chúng tôi phát hiện các tham số tùy chọn (ParameterInfo p.IsOptional) và đặt giá trị mặc định. Mục tiêu là đánh dấu các tham số là tùy chọn mà không cần dùng đến các loại như có "tùy chọn" trong tên tham số.


4
Nhưng làm thế nào để sử dụng chức năng Foo rồi? Foo (1,1); foo (1,1, null) và foo (1,1, Missing.value) đều sẽ ném ngoại lệ
Bolu

2
Lạ thật, Một số câu trả lời ở trên tốt hơn nhiều so với điều này.
Maidot

26

Bạn có thể sử dụng phương thức nạp chồng ...

GetFooBar ()
GetFooBar (int a)
GetFooBar (int a, int b)

Nó phụ thuộc vào chữ ký của phương thức, ví dụ tôi đã đưa ra thiếu phương thức "int b" bởi vì nó sẽ có cùng chữ ký với phương thức "int a".

Bạn có thể sử dụng các loại Nullable ...

GetFooBar (int? A, int? B)

Sau đó, bạn có thể kiểm tra, sử dụng a.HasValue, để xem liệu một tham số đã được đặt chưa.

Một tùy chọn khác là sử dụng tham số 'params'.

GetFooBar (đối tượng params [] args)

Nếu bạn muốn đi với các tham số được đặt tên sẽ cần phải tạo một loại để xử lý chúng, mặc dù tôi nghĩ rằng đã có một cái gì đó như thế này cho các ứng dụng web.


24

Bạn có thể sử dụng các tham số tùy chọn trong C # 4.0 mà không phải lo lắng. Nếu chúng ta có một phương thức như:

int MyMetod(int param1, int param2, int param3=10, int param4=20){....}

Khi bạn gọi phương thức, bạn có thể bỏ qua các tham số như thế này:

int variab = MyMethod(param3:50; param1:10);

C # 4.0 thực hiện một tính năng gọi là "tham số có tên", bạn thực sự có thể truyền tham số theo tên của chúng và tất nhiên bạn có thể truyền tham số theo bất kỳ thứ tự nào bạn muốn :)


20

Xin chào thế giới tùy chọn

Nếu bạn muốn bộ thực thi cung cấp một giá trị tham số mặc định, bạn phải sử dụng sự phản chiếu để thực hiện cuộc gọi. Không đẹp như những gợi ý khác cho câu hỏi này, nhưng tương thích với VB.NET.

using System;
using System.Runtime.InteropServices;
using System.Reflection;

namespace ConsoleApplication1
{
    class Class1
    {
        public static void sayHelloTo(
            [Optional,
            DefaultParameterValue("world")] string whom)
        {
            Console.WriteLine("Hello " + whom);
        }

        [STAThread]
        static void Main(string[] args)
        {
            MethodInfo mi = typeof(Class1).GetMethod("sayHelloTo");
            mi.Invoke(null, new Object[] { Missing.Value });
        }
    }
}

16

Một cách dễ dàng cho phép bạn bỏ qua bất kỳ tham số nàobất kỳ vị trí nào , đó là tận dụng các loại không thể thực hiện được như sau:

public void PrintValues(int? a = null, int? b = null, float? c = null, string s = "")
{
    if(a.HasValue)
        Console.Write(a);
    else
        Console.Write("-");

    if(b.HasValue)
        Console.Write(b);
    else
        Console.Write("-");

    if(c.HasValue)
        Console.Write(c);
    else
        Console.Write("-");

    if(string.IsNullOrEmpty(s)) // Different check for strings
        Console.Write(s);
    else
        Console.Write("-");
}

Chuỗi đã là loại nullable vì vậy họ không cần ? .

Khi bạn có phương thức này, các cuộc gọi sau đây đều hợp lệ :

PrintValues (1, 2, 2.2f);
PrintValues (1, c: 1.2f);
PrintValues(b:100);
PrintValues (c: 1.2f, s: "hello");
PrintValues();

Khi bạn xác định một phương thức theo cách bạn có quyền tự do chỉ đặt các tham số bạn muốn bằng cách đặt tên cho chúng. Xem liên kết sau để biết thêm thông tin về các tham số được đặt tên và tùy chọn:

Các đối số được đặt tên và tùy chọn (Hướng dẫn lập trình C #) @ MSDN


9

Tôi đồng ý với stephenbayer. Nhưng vì là dịch vụ web, người dùng cuối sẽ dễ dàng sử dụng chỉ một hình thức của webmethod, hơn là sử dụng nhiều phiên bản của cùng một phương thức. Tôi nghĩ rằng trong tình huống này, các loại Nullable là hoàn hảo cho các tham số tùy chọn.

public void Foo(int a, int b, int? c)
{
  if(c.HasValue)
  {
    // do something with a,b and c
  }
  else
  {
    // do something with a and b only
  }  
}

+1 Lời khuyên mặc dù. Đừng biến điều này thành thói quen vì nó có thể trở nên thực sự lộn xộn.
mhenrixon

7

tham số tùy chọn là cho các phương thức. nếu bạn cần các đối số tùy chọn cho một lớp và bạn là:

  • sử dụng c # 4.0: sử dụng các đối số tùy chọn trong hàm tạo của lớp, một giải pháp tôi thích, vì nó gần với những gì được thực hiện bằng các phương thức, do đó dễ nhớ hơn. đây là một ví dụ:

    class myClass
    {
        public myClass(int myInt = 1, string myString =
                               "wow, this is cool: i can have a default string")
        {
            // do something here if needed
        }
    }
  • sử dụng các phiên bản c # trước c # 4.0: bạn nên sử dụng chuỗi xây dựng (sử dụng: từ khóa này), trong đó các hàm tạo đơn giản hơn dẫn đến "hàm tạo chính". thí dụ:

    class myClass
    {
        public myClass()
        {
        // this is the default constructor
        }
    
        public myClass(int myInt)
            : this(myInt, "whatever")
        {
            // do something here if needed
        }
        public myClass(string myString)
            : this(0, myString)
        {
            // do something here if needed
        }
        public myClass(int myInt, string myString)
        {
            // do something here if needed - this is the master constructor
        }
    }

3

Cách điển hình này được xử lý trong C # như đã đề cập đến là quá tải phương thức. Bằng cách tạo nhiều phiên bản của phương thức với các tham số khác nhau, bạn tạo hiệu quả các tham số tùy chọn. Trong các biểu mẫu có ít tham số hơn, bạn thường gọi dạng của phương thức với tất cả các tham số đặt giá trị mặc định của bạn trong lệnh gọi phương thức đó.


2

Bạn có thể quá tải phương pháp của bạn. Một phương thức chứa một tham số GetFooBar(int a)và phương thức kia chứa cả hai tham số,GetFooBar(int a, int b)


2

Sử dụng quá tải hoặc sử dụng C # 4.0 trở lên

 private void GetVal(string sName, int sRoll)
 {
   if (sRoll > 0)
   {
    // do some work
   }
 }

 private void GetVal(string sName)
 {
    GetVal("testing", 0);
 }

1

Đối với số lượng lớn hơn các tham số tùy chọn, một tham số Từ điển có thể được sử dụng với phương thức ContainsKey. Tôi thích cách tiếp cận này vì nó cho phép tôi vượt qua Danh sách hoặc T riêng lẻ mà không phải tạo toàn bộ phương thức khác (chẳng hạn nếu tham số được sử dụng làm bộ lọc chẳng hạn).

Ví dụ (Từ điển mới <chuỗi, Object> () sẽ được thông qua nếu không có tham số tùy chọn nào được mong muốn):

public bool Method(string ParamA, Dictionary<string,Object> AddlParams) {
    if(ParamA == "Alpha" && (AddlParams.ContainsKey("foo") || AddlParams.ContainsKey("bar"))) {
        return true;
    } else {
        return false;
    }
}

0

Thay vì các tham số mặc định, tại sao không chỉ xây dựng một lớp từ điển từ chuỗi truy vấn được truyền .. một triển khai gần giống với cách các biểu mẫu asp.net hoạt động với các truy vấn.

tức là Request.QueryString ["a"]

Điều này sẽ tách lớp lá từ mã nhà máy / nồi hơi.


Bạn cũng có thể muốn kiểm tra Dịch vụ web với ASP.NET . Các dịch vụ web là một api web được tạo tự động thông qua các thuộc tính trên các lớp C #.


0

Đến bữa tiệc muộn một chút, nhưng tôi đang tìm câu trả lời cho câu hỏi này và cuối cùng đã tìm ra một cách khác để làm điều này. Khai báo các kiểu dữ liệu cho các đối số tùy chọn của phương thức web của bạn là loại XmlNode. Nếu đối số tùy chọn bị bỏ qua, điều này sẽ được đặt thành null và nếu có, bạn có thể nhận được giá trị chuỗi bằng cách gọi arg.Value, nghĩa là,

[WebMethod]
public string Foo(string arg1, XmlNode optarg2)
{
    string arg2 = "";
    if (optarg2 != null)
    {
        arg2 = optarg2.Value;
    }
    ... etc
}

Điều cũng phù hợp với cách tiếp cận này là trang chủ được tạo .NET cho ws vẫn hiển thị danh sách đối số (mặc dù bạn mất các hộp nhập văn bản tiện dụng để kiểm tra).


3
Điều này có tốt hơn so với việc sử dụng các loại nullable?
Kirk Broadhurst

0

Tôi có một dịch vụ web để viết có 7 tham số. Mỗi là một thuộc tính truy vấn tùy chọn cho một câu lệnh sql được bao bọc bởi dịch vụ web này. Vì vậy, hai cách giải quyết cho các thông số không tùy chọn xuất hiện trong tâm trí ... cả hai đều khá nghèo:

phương thức 1 (param1, param2, param 3, param 4, param 5, param 6, param7) phương thức1 (param1, param2, param3, param 4, param5, param 6) phương thức 1 (param1, param2, param3, param4, param5, param7 ) ... bắt đầu để xem hình ảnh. Cách này nằm điên rồ. Cách quá nhiều kết hợp.

Bây giờ đối với một cách đơn giản hơn có vẻ khó xử nhưng nên hoạt động: phương thức1 (param1, bool useParam1, param2, bool useParam2, v.v ...)

Đó là một cuộc gọi phương thức, các giá trị cho tất cả các tham số là bắt buộc và nó sẽ xử lý từng trường hợp bên trong nó. Nó cũng rõ ràng làm thế nào để sử dụng nó từ giao diện.

Đó là một hack, nhưng nó sẽ hoạt động.


2
Đây là lý do tại sao các tham số nullable tồn tại.
Kirk Broadhurst

0

Tôi đã phải làm điều này trong một dịch vụ web VB.Net 2.0. Tôi đã kết thúc việc chỉ định các tham số dưới dạng chuỗi, sau đó chuyển đổi chúng thành bất cứ thứ gì tôi cần. Một tham số tùy chọn đã được chỉ định với một chuỗi rỗng. Không phải là giải pháp sạch nhất, nhưng nó đã làm việc. Chỉ cần cẩn thận rằng bạn nắm bắt tất cả các ngoại lệ có thể xảy ra.


0

Đối với chỉ trong trường hợp nếu ai đó muốn vượt qua một cuộc gọi lại (hoặc delegate) như một tham số tùy chọn, có thể thực hiện theo cách này.

Tham số gọi lại tùy chọn:

public static bool IsOnlyOneElement(this IList lst, Action callbackOnTrue = (Action)((null)), Action callbackOnFalse = (Action)((null)))
{
    var isOnlyOne = lst.Count == 1;
    if (isOnlyOne && callbackOnTrue != null) callbackOnTrue();
    if (!isOnlyOne && callbackOnFalse != null) callbackOnFalse();
    return isOnlyOne;
}

0

tham số tùy chọn không có gì ngoài tham số mặc định! tôi đề nghị bạn cung cấp cho cả hai tham số mặc định. GetFooBar (int a = 0, int b = 0) nếu bạn không có bất kỳ phương thức quá tải nào, sẽ dẫn đến a = 0, b = 0 nếu bạn không vượt qua bất kỳ giá trị nào, nếu bạn vượt qua 1 giá trị, sẽ dẫn đến , đã chuyển giá trị cho a, 0 và nếu bạn vượt qua 2 giá trị thứ 1 sẽ được gán cho a và thứ hai cho b.

Hy vọng rằng câu trả lời câu hỏi của bạn.


0

Trong trường hợp khi các giá trị mặc định không có sẵn, cách để thêm một tham số tùy chọn là sử dụng lớp .NET OptionsAttribution - https://docs.microsoft.com/en-us/dotnet/api/system.r nb.interopservice.optionalattribution ? view = netframework-4.8

Ví dụ về mã dưới đây:

namespace OptionalParameterWithOptionalAttribute
{
    class Program
    {
        static void Main(string[] args)
        {
            //Calling the helper method Hello only with required parameters
            Hello("Vardenis", "Pavardenis");
            //Calling the helper method Hello with required and optional parameters
            Hello("Vardenis", "Pavardenis", "Palanga");
        }
        public static void Hello(string firstName, string secondName, 
            [System.Runtime.InteropServices.OptionalAttribute] string  fromCity)
        {
            string result = firstName + " " + secondName;
            if (fromCity != null)
            {
                result += " from " + fromCity;
            }
            Console.WriteLine("Hello " + result);
        }

    }
}

-4

Bạn cũng có thể thử
loại 1
public void YourMethod(int a=0, int b = 0) { //some code }


Loại 2
public void YourMethod(int? a, int? b) { //some code }

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.