Bu sorunun C ++ sürümünü okudum ama gerçekten anlamadım.
Birisi bunun nasıl yapılacağını ve nasıl yapılacağını açık bir şekilde açıklayabilir mi?
Bu sorunun C ++ sürümünü okudum ama gerçekten anlamadım.
Birisi bunun nasıl yapılacağını ve nasıl yapılacağını açık bir şekilde açıklayabilir mi?
Yanıtlar:
C # 7 ve üstü için bu cevaba bakınız .
Önceki sürümlerde, .NET 4.0 + 's Tuple'ı kullanabilirsiniz :
Örneğin:
public Tuple<int, int> GetMultipleValue()
{
return Tuple.Create(1,2);
}
İki değer var olan Tuplelar Item1
ve Item2
özellikler olarak.
public (int sum, int count) GetMultipleValues() { return (1, 2); }
Bu örnek, bununla ilgili Belgeler konu örneğimizden alınmıştır .
Şimdi C # 7 yayınlandığına göre, yeni eklenen Tuples sözdizimini kullanabilirsiniz
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
daha sonra şu şekilde kullanılabilir:
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Öğelerinize ad da verebilirsiniz (bu nedenle "Öğe1", "Öğe2" vb. Değildir). İmzaya veya iade yöntemlerine bir ad ekleyerek bunu yapabilirsiniz:
(string first, string middle, string last) LookupName(long id) // tuple elements have names
veya
return (first: first, middle: middle, last: last); // named tuple elements in a literal
Ayrıca yapısız olabilirler, bu oldukça güzel bir yeni özelliktir:
(string first, string middle, string last) = LookupName(id1); // deconstructing declaration
Neler yapılabileceğine ilişkin daha fazla örnek görmek için bu bağlantıya göz atın :)
Üç farklı yol kullanabilirsiniz
1. ref / out parametreleri
ref kullanarak:
static void Main(string[] args)
{
int a = 10;
int b = 20;
int add = 0;
int multiply = 0;
Add_Multiply(a, b, ref add, ref multiply);
Console.WriteLine(add);
Console.WriteLine(multiply);
}
private static void Add_Multiply(int a, int b, ref int add, ref int multiply)
{
add = a + b;
multiply = a * b;
}
kullanarak:
static void Main(string[] args)
{
int a = 10;
int b = 20;
int add;
int multiply;
Add_Multiply(a, b, out add, out multiply);
Console.WriteLine(add);
Console.WriteLine(multiply);
}
private static void Add_Multiply(int a, int b, out int add, out int multiply)
{
add = a + b;
multiply = a * b;
}
2. yapı / sınıf
struct kullanarak:
struct Result
{
public int add;
public int multiply;
}
static void Main(string[] args)
{
int a = 10;
int b = 20;
var result = Add_Multiply(a, b);
Console.WriteLine(result.add);
Console.WriteLine(result.multiply);
}
private static Result Add_Multiply(int a, int b)
{
var result = new Result
{
add = a * b,
multiply = a + b
};
return result;
}
sınıf kullanma:
class Result
{
public int add;
public int multiply;
}
static void Main(string[] args)
{
int a = 10;
int b = 20;
var result = Add_Multiply(a, b);
Console.WriteLine(result.add);
Console.WriteLine(result.multiply);
}
private static Result Add_Multiply(int a, int b)
{
var result = new Result
{
add = a * b,
multiply = a + b
};
return result;
}
3. Demet
Tuple sınıfı
static void Main(string[] args)
{
int a = 10;
int b = 20;
var result = Add_Multiply(a, b);
Console.WriteLine(result.Item1);
Console.WriteLine(result.Item2);
}
private static Tuple<int, int> Add_Multiply(int a, int b)
{
var tuple = new Tuple<int, int>(a + b, a * b);
return tuple;
}
C # 7 Tuples
static void Main(string[] args)
{
int a = 10;
int b = 20;
(int a_plus_b, int a_mult_b) = Add_Multiply(a, b);
Console.WriteLine(a_plus_b);
Console.WriteLine(a_mult_b);
}
private static (int a_plus_b, int a_mult_b) Add_Multiply(int a, int b)
{
return(a + b, a * b);
}
Bunu C # ile yapamazsınız. Yapabileceğiniz şey, bir out
parametreye sahip olmak veya kendi sınıfınızı döndürmektir (veya değişmez olmasını istiyorsanız, yapı).
public int GetDay(DateTime date, out string name)
{
// ...
}
Özel sınıf (veya yapı) kullanma
public DayOfWeek GetDay(DateTime date)
{
// ...
}
public class DayOfWeek
{
public int Day { get; set; }
public string Name { get; set; }
}
async
yöntemlerle mümkün değildir . Tuple
gitmek için bir yoldur. ( out
Eşzamanlı işlemlerde parametreleri kullanıyorum ; bu durumlarda gerçekten yararlılar.)
Birden çok değer döndürmek istiyorsanız, döndürmek istediğiniz değerleri içeren bir sınıf / yapı döndürebilir veya parametrelerinizdeki "out" anahtar kelimesini şu şekilde kullanabilirsiniz:
public void Foo(int input, out int output1, out string output2, out string errors) {
// set out parameters inside function
}
Önceki poster doğru. Bir C # yönteminden birden çok değer döndüremezsiniz. Ancak, birkaç seçeneğiniz var:
Buradaki artıları ve eksileri anlamak genellikle zordur. Bir yapı döndürürseniz, yapıların değer türü olduğu ve yığına iletildiği için küçük olduğundan emin olun. Bir sınıf örneğini döndürürseniz, sorunlara neden olmamak için burada kullanmak isteyebileceğiniz bazı tasarım desenleri vardır - C # nesneleri referans ile geçtiğinden sınıf üyeleri değiştirilebilir (VB'de yaptığınız gibi ByVal'a sahip değilsiniz) ).
Son olarak çıkış parametrelerini kullanabilirsiniz, ancak parametrelerin yalnızca birkaçı (3 veya daha az gibi) olduğunda senaryolarla sınırlı kalırım - aksi takdirde işler çirkin ve bakımı zorlaşır. Ayrıca, çıktı parametrelerinin kullanımı çeviklik için bir engelleyici olabilir, çünkü yöntem imzanız, dönüş değerine her şey eklemeniz gerektiğinde değişmek zorunda kalacakken, bir yapı veya sınıf örneğini döndürmek için yöntem imzasını değiştirmeden üye ekleyebilirsiniz.
Mimari açıdan, anahtar / değer çiftlerini veya sözlükleri kullanmamanızı tavsiye ederim. Ben bu kodlama tarzı yöntemi tüketen kod "gizli bilgi" gerektirir bulmak. Anahtarların ne olacağını ve değerlerin ne anlama geldiğini önceden bilmelidir ve dahili uygulamada çalışan geliştirici, sözlük veya KVP'nin oluşturulma şeklini değiştirirse, tüm uygulama boyunca kolayca bir hata kademesi oluşturabilir.
Exception
, döndürmek istediğiniz ikinci değerin ilk değerden kopması durumunda bir de atayabilirsiniz: bir tür başarılı değer veya bir tür başarısız değer döndürmek istediğinizde olduğu gibi.
Ya bir dönüş sınıf örneğini veya kullanım dışarı parametrelerini. Out parametrelerine bir örnek:
void mymethod(out int param1, out int param2)
{
param1 = 10;
param2 = 20;
}
Buna şöyle deyin:
int i, j;
mymethod(out i, out j);
// i will be 20 and j will be 10
Birçok yol var; ancak yeni bir Nesne veya yapı veya bunun gibi bir şey oluşturmak istemiyorsanız, C # 7.0'dan sonra aşağıdaki gibi yapabilirsiniz :
(string firstName, string lastName) GetName(string myParameter)
{
var firstName = myParameter;
var lastName = myParameter + " something";
return (firstName, lastName);
}
void DoSomethingWithNames()
{
var (firstName, lastName) = GetName("myname");
}
C # 7'de yeni bir Tuple
sözdizimi var:
static (string foo, int bar) GetTuple()
{
return ("hello", 5);
}
Bunu bir kayıt olarak döndürebilirsiniz:
var result = GetTuple();
var foo = result.foo
// foo == "hello"
Yeni yapısökücü sözdizimini de kullanabilirsiniz:
(string foo) = GetTuple();
// foo == "hello"
Ancak serileştirme dikkatli olun, bütün bu sözdizimsel şeker - gerçek derlenmiş kod bu olacak Tuple<string, int>
(aynı kabul Yanıt başına birlikte) Item1
ve Item2
yerine foo
vebar
. Bu, serileştirmenin (veya serileştirmenin) bunun yerine bu özellik adlarını kullanacağı anlamına gelir.
Yani, serileştirme için bir kayıt sınıfı bildirin ve bunun yerine geri gönderin.
Ayrıca C # 7'de yeni olan, out
parametreler için geliştirilmiş bir sözdizimidir . Artık out
bazı bağlamlarda daha uygun olan satır içi bildirebilirsiniz :
if(int.TryParse("123", out int result)) {
// Do something with result
}
Ancak, bunu çoğunlukla kendi işlevleriniz yerine .NET'in kendi kitaplıklarında kullanırsınız.
Bazı cevaplar parametrelerin kullanılmasını önermez, ancak zaman uyumsuz yöntemlerle çalışmadığı için bunu kullanmamanızı öneririm . Bkz bu fazla bilgi için.
Diğer cevaplar da ben tavsiye ederim ama C # 7.0 ile sunulan yeni özelliği kullanarak Tuple kullanarak belirtti.
(string, string, string) LookupName(long id) // tuple return type
{
... // retrieve first, middle and last from data storage
return (first, middle, last); // tuple literal
}
var names = LookupName(id);
WriteLine($"found {names.Item1} {names.Item3}.");
Daha fazla bilgi burada bulunabilir .
Bunu yapmanın birkaç yolu vardır. ref
Parametreleri kullanabilirsiniz :
int Foo(ref Bar bar) { }
Bu, işleve bir başvuru ileterek işlevin çağrı kodunun yığınındaki nesneyi değiştirmesine izin verir. Bu teknik olarak "döndürülen" bir değer olmamakla birlikte, bir işleve benzer bir şey yapmanın bir yoludur. Yukarıdaki kodda, işlev bir int
ve (potansiyel olarak) bir değişiklik döndürür bar
.
Bir diğer benzer yaklaşım bir out
parametre kullanmaktır . Bir out
parametre özdeş ref
ek bir derleyici zorlanan kurala parametresi. Bu kural, bir out
parametreye bir işleve iletirseniz, geri dönmeden önce değerini ayarlamak için bu işlevin gerekli olmasıdır. Bu kuralın yanı sıra, bir out
parametre tıpkı bir ref
parametre gibi çalışır .
Son yaklaşım (ve çoğu durumda en iyisi) her iki değeri de içine alan ve işlevin bunu döndürmesine izin veren bir tür oluşturmaktır:
class FooBar
{
public int i { get; set; }
public Bar b { get; set; }
}
FooBar Foo(Bar bar) { }
Bu son yaklaşım daha basit ve okunması ve anlaşılması daha kolaydır.
Hayır, C # 'daki bir işlevden (C # 7'den düşük sürümler için) birden çok değer döndüremezsiniz, en azından Python'da yapabileceğiniz şekilde değil.
Ancak, birkaç alternatif var:
İstediğiniz birden çok değeri içeren bir yazı tipi dizisi döndürebilirsiniz.
private object[] DoSomething()
{
return new [] { 'value1', 'value2', 3 };
}
out
Parametreleri kullanabilirsiniz .
private string DoSomething(out string outparam1, out int outparam2)
{
outparam1 = 'value2';
outparam2 = 3;
return 'value1';
}
C # 4'te, bunu kolayca halletmek için tuples için yerleşik desteği kullanabilirsiniz.
Bu arada iki seçenek var.
İlk olarak, parametrelerinize arama rutinine geri gönderilen değerleri atamak için ref veya out parametrelerini kullanabilirsiniz.
Bu şuna benzer:
void myFunction(ref int setMe, out int youMustSetMe);
İkincisi, dönüş değerlerinizi bir yapıya veya sınıfa sarıp bunları o yapının üyeleri olarak iletebilirsiniz. KeyValuePair 2 için iyi çalışır - 2'den fazla için özel bir sınıfa veya yapıya ihtiyacınız olacaktır.
bunu "KeyValuePair" deneyebilirsiniz
private KeyValuePair<int, int> GetNumbers()
{
return new KeyValuePair<int, int>(1, 2);
}
var numbers = GetNumbers();
Console.WriteLine("Output : {0}, {1}",numbers.Key, numbers.Value);
Çıktı :
Çıkış: 1, 2
Sınıflar, Yapılar, Koleksiyonlar ve Diziler birden çok değer içerebilir. Çıkış ve referans parametreleri de bir fonksiyonda ayarlanabilir. Birden fazla değer döndürmek, tuples aracılığıyla dinamik ve fonksiyonel dillerde mümkündür, ancak C # 'de mümkün değildir.
Temelde iki yöntem vardır. 1. out / ref parametrelerini kullanma 2. Nesneler dizisi döndürme
İşte temel Two
yöntemler:
1) 'Kullanımıout
Parametre olarak '
kullanımı Hem 4.0 hem de küçük sürümler için de 'out' kullanabilirsiniz.
'Out' örneği:
using System;
namespace out_parameter
{
class Program
{
//Accept two input parameter and returns two out value
public static void rect(int len, int width, out int area, out int perimeter)
{
area = len * width;
perimeter = 2 * (len + width);
}
static void Main(string[] args)
{
int area, perimeter;
// passing two parameter and getting two returning value
Program.rect(5, 4, out area, out perimeter);
Console.WriteLine("Area of Rectangle is {0}\t",area);
Console.WriteLine("Perimeter of Rectangle is {0}\t", perimeter);
Console.ReadLine();
}
}
}
Çıktı:
Dikdörtgen Alanı 20
Dikdörtgenin Çevresi 18
* Not: *out
-keyword, gerçek değişken konumları çağrılan yöntemin yığınına kopyalanan ve aynı konumların yeniden yazılabildiği parametreleri açıklar. Bu, çağıran yöntemin değiştirilen parametreye erişeceği anlamına gelir.
2) Tuple<T>
Tuple örneği:
Kullanarak Birden Çok DataType değeri döndürme Tuple<T>
using System;
class Program
{
static void Main()
{
// Create four-item tuple; use var implicit type.
var tuple = new Tuple<string, string[], int, int[]>("perl",
new string[] { "java", "c#" },
1,
new int[] { 2, 3 });
// Pass tuple as argument.
M(tuple);
}
static void M(Tuple<string, string[], int, int[]> tuple)
{
// Evaluate the tuple's items.
Console.WriteLine(tuple.Item1);
foreach (string value in tuple.Item2)
{
Console.WriteLine(value);
}
Console.WriteLine(tuple.Item3);
foreach (int value in tuple.Item4)
{
Console.WriteLine(value);
}
}
}
Çıktı
perl
java
c#
1
2
3
Not: Tuple kullanımı, Framework 4.0 ve sonraki sürümleri için geçerlidir . Tuple
türü bir class
. Bellekte yönetilen yığın üzerinde ayrı bir yere tahsis edilecektir. Bir kez oluşturduğunuzda Tuple
, değerini değiştiremezsiniz fields
. Bu Tuple
daha çok a struct
.
Bir temsilci alan bir yöntem arayan kişiye birden çok değer sağlayabilir. Bu, buradaki cevabımdan ödünç alıyor ve Hadas'ın kabul edilen cevabından biraz kullanıyor .
delegate void ValuesDelegate(int upVotes, int comments);
void GetMultipleValues(ValuesDelegate callback)
{
callback(1, 2);
}
Arayanlar bir lambda (veya adlandırılmış bir işlev) sağlar ve intellisense, değişken adlarını temsilciden kopyalayarak yardımcı olur.
GetMultipleValues((upVotes, comments) =>
{
Console.WriteLine($"This post has {upVotes} Up Votes and {comments} Comments.");
});
Sadece OOP tarzında aşağıdaki gibi bir sınıf kullanın:
class div
{
public int remainder;
public int quotient(int dividend, int divisor)
{
remainder = ...;
return ...;
}
}
İşlev üyesi, çoğu arayanın öncelikli olarak ilgilendiği bölümü döndürür. Ek olarak, geri kalanını, arayan tarafından daha sonra kolayca erişilebilen bir veri üyesi olarak depolar.
Bu şekilde, birçok hata mesajının gerekli olabileceği ancak yalnızca bir hata oluştuğunda veritabanı veya ağ çağrıları uygularsanız çok yararlı olan birçok "dönüş değeri" elde edebilirsiniz.
Bu çözümü OP'nin atıfta bulunduğu C ++ sorusuna da girdim.
C # 'ın gelecekteki sürümü adlandırılmış tuples içerecek. Demo için bu kanal 9 oturumuna göz atın https://channel9.msdn.com/Events/Build/2016/B889
Tuple şeyler için 13: 00'a atlayın. Bu, aşağıdaki gibi şeylere izin verecektir:
(int sum, int count) Tally(IEnumerable<int> list)
{
// calculate stuff here
return (0,0)
}
int resultsum = Tally(numbers).sum
(videodan eksik örnek)
Dinamik bir nesne kullanabilirsiniz. Bence Tuple'dan daha iyi okunabilirliğe sahip.
static void Main(string[] args){
var obj = GetMultipleValues();
Console.WriteLine(obj.Id);
Console.WriteLine(obj.Name);
}
private static dynamic GetMultipleValues() {
dynamic temp = new System.Dynamic.ExpandoObject();
temp.Id = 123;
temp.Name = "Lorem Ipsum";
return temp;
}
Bunu yapmanın yolları:
1) KeyValuePair (En İyi Performans - 0,32 ns):
KeyValuePair<int, int> Location(int p_1, int p_2, int p_3, int p_4)
{
return new KeyValuePair<int,int>(p_2 - p_1, p_4-p_3);
}
2) Tuple - 5.40 ns:
Tuple<int, int> Location(int p_1, int p_2, int p_3, int p_4)
{
return new Tuple<int, int>(p_2 - p_1, p_4-p_3);
}
3) out (1.64 ns) veya ref 4) Kendi özel sınıfınızı / yapınızı oluşturun
ns -> nanosaniye
Referans: çoklu-dönüş-değerleri .
bunu deneyebilirsin
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
yield return "value1"; yield return "value2";
açıkça yeni bir tane oluşturmak zorunda kalmıyorsunuz string[]
?
Bir OperationResult da kullanabilirsiniz
public OperationResult DoesSomething(int number1, int number2)
{
// Your Code
var returnValue1 = "return Value 1";
var returnValue2 = "return Value 2";
var operationResult = new OperationResult(returnValue1, returnValue2);
return operationResult;
}
Dizi türü için özel olarak hızlı bir yanıt döndürür:
private int[] SumAndSub(int A, int B)
{
return new[] { A + B, A - B };
}
Kullanımı:
var results = SumAndSub(20, 5);
int sum = results[0];
int sub = results[1];