PDA

View Full Version : ارسال یک شی از کلاس جنریک به کلاس دیگه (حرفه ای!)



Mrs.Net
جمعه 07 تیر 1387, 16:22 عصر
یکم گیچ شدم :(

یک کلاس جنریک (تقریبا کارش مشابه با List<> هست) دارم بنام مای جنریک
Class MyGeneric<T>
یک کلاس هم دارم بنام کلاس بی
ClassB
یک کلاس ساختم به اسم کلاس آ به این صورت

ClassA : MyGeneric<ClassB>
پس کلاس آ لیستی از کلاس بی هست.
خوب حالا:
یک شی ساختم از نوع کلاس آ و میخوام این شی به یک کلاس دیگه پاس بدم ولی فقط میدونم که شیی که دارم میگیرم بیسش از نوع جنریک هست. همین.

پس نمیتونم بنویسم :

public void GetObject(ClassA obj)

میتونم بنویسم :

public void GetObject(Object list, Type typeOfList)
اما نتونستم ازش استفاده کنم. چون میخوام به ازای هر عضو این شی ورودی یه کاری انجام بدم.

اگر نفهمیدید باز توضیح میدم.

رضا عربلو
جمعه 07 تیر 1387, 20:22 عصر
از کلمه کلیدی WHERE استفاده کن. به این صورت


ClassA : MyGeneric<T> WHERE T:CLassB

Mrs.Net
جمعه 07 تیر 1387, 21:50 عصر
خوب این خط چجوری کاری که من میخوام انجام میده؟!

ASKaffash
شنبه 08 تیر 1387, 08:23 صبح
سلام
بیشتر توضیح دهید چون کد ذیل مشابه دستور شما خطائی ندارد!


class B
{
public int i = 0;
}
class MyGeneric<T>
{
public int j = 0;
}
class A : MyGeneric<B>
{
public void f()
{
}
}
class D
{
void g(A a)
{
a.j = 10;
}
}

Mrs.Net
شنبه 08 تیر 1387, 09:17 صبح
بله این کد شما درست کار میکنه ولی چیزی که من میخوام :

ولی فقط میدونم که شیی که دارم میگیرم بیسش از نوع جنریک هست. همین.

یعنی همین کدی که شما نوشتید ولی متد g رو نمیتونید اینجوری بنویسید چون یک کلاس دیگه هم شبیه کلاس آ هست که از بیس جنریک ساخته شده و نکته بدترش اینه که مقدار جنریکش هم کلاس B نیست
مثال:

Class C : MyGeneric<E>
خوب اینو چجوری میخواید به g پاس بدید؟
پس تابع g رو تغییر بدید که فقط ورودیش به کلاس آ محدود نشه.

ASKaffash
شنبه 08 تیر 1387, 12:17 عصر
سلام
نظرت در باره این کد چیه ؟ آیا شبیه است ؟


class B1
{
public int i1 = 0;
}
class B2
{
public int i2 = 0;
}
class MyGeneric<T>
{
public int j = 0;
}
class A<U> : MyGeneric<U>
{
public void f(U u)
{
}
}
class D
{
void g1(A<B1> a)
{
a.f(new B1());
}
void g2(A<B2> a)
{
a.f(new B2());
}
}

Mrs.Net
شنبه 08 تیر 1387, 12:36 عصر
یعنی من بیام برای هر کدام از 20 نوع کلاسم که ممکنه در مدت برنامه نویسی بیشتر هم بشه یک تابع تو کلاس D بنویسم و مهمتر از اون برای تمام توابع یک بدنه (کار یکسان) رو پیاده سازی کنم؟!!

ASKaffash
شنبه 08 تیر 1387, 12:47 عصر
سلام
من اینو نگفتم . شما ورودی تابع شما میتواند کاملا متغیر باشد وهر نوعی که از طریق A دریافت کنید بصورت پویا به کلاس MyGeneric شما ارسال میگردد پس همانطور که میبینید ورودی تابعهای شما یکبار با B1 و یکبار با B2 است (OverLoading) است .


class D
{
void g(A<B1> a)
{
a.f(new B1());
}
void g(A<B2> a)
{
a.f(new B2());
}
}

Mrs.Net
شنبه 08 تیر 1387, 16:54 عصر
فکر کنم مسیر اشتباه داریم میریم.

class MyGeneric<T>
class B1
class B2
class B3
....
class A1 : MyGeneric<B1>
class A2 : MyGeneric<B2>
class A3 : MyGeneric<B3>
....

class Operation{
public void Do(......){
//این تابع با مرودیهایی که از نوع MyGeneric باشه کار میکنه
//و به نوع پارامتر جنریک و خود کلاس احتیاج داره.
}
}


خوب حالا نحوه استفاده:

class MyForm:Form{
private void Test(){
Operation ope=new Operation();
A1 obja1=new A1();
A2 obja2=new A2();
A3 obja3=new A3();

ope.Do(... obja1...);
ope.Do(... obja2...);
ope.Do(... obja3...);

}
}

و تابع Do فقط یکبار نوشته بشه (چون خودش 30 40 تا خط داره)
و درضمن فرض کنید این کلاسهای A و B نامحدود هستند. (این منطق برنامه نویسی پارامتریک هست که مقصد به مبدا وابسته نباشه)

ASKaffash
یک شنبه 09 تیر 1387, 10:03 صبح
سلام
پس پای Reflection باز شد:


class MyGeneric<T>
{ public int i = 10; }
class B1 { }
class B2 { }
class B3 { }
class A1 : MyGeneric<B1> { }
class A2 : MyGeneric<B2> { }
class A3 : MyGeneric<B3> { }
class Operation
{
public string Do(object a)
{
return a.GetType().GetField("i").GetValue(a).ToString();
}
}



Operation ope=new Operation();
A1 obja1=new A1();
A2 obja2=new A2();
A3 obja3=new A3();
this.Text = ope.Do(obja1);

Mrs.Net
یک شنبه 09 تیر 1387, 13:43 عصر
خوب تازه مشخص شد که من تقریبا چی منظورم بوده.
میریم ستپ بعدی که تو سوالم هم گفته بودم:
این کلاس MyGeneric مثل کلاس List عمل میکنه. یعنی کلاس A شامل لیستی از کلاس B هست. مثل:

Class A1:List<B1> { }
خوب حالا تابع Do باید به ازای هر عضو B1 داخل شی obja1 یکاری انجام بده و کارشم اینه که پارامتری از اون کلاس رو چاپ کنه.

foreach (B1 objb1 in obja1){
consol.write(objb1["parameterb1"])
}

البته اسم پارامتری که باید چاپ شه به تابع Do ارسال میشه پس نگرانش نباشید.
تنها مسئله همون foreach هست که B1 رو ما نمیدونیم.

رضا عربلو
دوشنبه 10 تیر 1387, 00:45 صبح
برای اینکه شما بتوانید دستور foreach را بکار ببرید نوع تان بایستی اینترفیس IEnumerable را پیاده سازی کند.
این هم یک آموزش ساده :
http://www.codeproject.com/KB/cs/csenumerators.aspx

ASKaffash
دوشنبه 10 تیر 1387, 08:00 صبح
سلام
من یک کم سئوال را دستکاری کرد فقط مشکل Cast کردن در بخش قرمز رنگ است آیا شما میتوانید این بخش را تصحیح کنید ؟ در ضمن باید کاری کرد که دیگران هم در این موضوع مشارکت کنند چون مبحث خیلی تکنیکی است.


class B1
{
public int b1 = 0;
public B1(int b1)
{ this.b1 = b1; }
}
class B2
{
public int b2 = 0;
public B2(int b2)
{ this.b2 = b2; }
}
class B3
{
public int b3 = 0;
public B3(int b3)
{ this.b3 = b3; }
}
class A1 : List<B1> { public int a1 = 1; }
class A2 : List<B2> { public int a2 = 2; }
class A3 : List<B3> { public int a3 = 3; }
class Operation
{
public string Do(object a,string f)
{
string s = "";
List<object> x = new List<object>();
x = (List<object>)a;
for (int i = 0; i < x.Count; i++)
s += x[i].GetType().GetField(f).GetValue(x[i]).ToString();
return s;
}
}



Operation ope=new Operation();
A1 o1=new A1();
A2 o2=new A2();
A3 o3=new A3();
o1.Add(new B1(10));
o1.Add(new B1(20));
o1.Add(new B1(30));
this.Text = ope.Do(o1, "b1");