سؤال

أنا أتساءل عما إذا كان التالي هو ممكن.إنشاء فئة يقبل مجهول نوع (سلسلة الباحث العشرية ، customObject ، الخ) ، ثم يكون طاقتها الأساليب التي تفعل عمليات مختلفة على أساس النوع.على سبيل المثال

    class TestClass<T>
{
  public void GetName<string>()
  {
      //do work knowing that the type is a string    
  }

  public string GetName<int>()
  {
      //do work knowing that the type is an int

  } 

  public string GetName<int>(int addNumber)
  {
      //do work knowing that the type is an int (overloaded)    
  } 

  public string GetName<DateTime>()
  {
      //do work knowing that the type is a DateTime

  } 

  public string GetName<customObject>()
  {
      //do work knowing that the type is a customObject type    
  }

}

حتى الآن أنا يمكن أن نسميه GetName الطريقة لأنني مرت بالفعل في نوع عندما تهيئة كائن الأسلوب الصحيح هو العثور على تنفيذها.

TestClass foo = new TestClass<int>();

//executes the second method because that's the only one with a "int" type
foo.GetName();

هل هذا ممكن أم أنني أحلم ؟

هل كانت مفيدة؟

المحلول

ما تحاول القيام به هو ممكن مثل هذا:

class TestClass<T>
{
   public string GetName<T>()
   {
      Type typeOfT = typeof(T);
      if(typeOfT == typeof(string))
      {
          //do string stuff
      }
   }
}

في حين أن هذا هو ممكن أنت نوع من هزيمة الغرض من الأدوية.نقطة من الأدوية هو عندما اكتب لا المسألة, لذلك أنا لا أعتقد الأدوية المناسبة في هذه الحالة.

نصائح أخرى

والتخصص غير ممكن في C #. أقرب شيء في C # هو التالي

public void Example() {
  public static void Method<T>(T value) { ... }
  public static void Method(int value){ ... }
  public static void Method(string) { ... }
}

و # مترجم C يفضلون أسلوب غير عامة على طريقة عام. وهذا يعني أن الدعوة مع مواضيعها كثافة العمليات سوف ربط الزائد كثافة مقابل واحد عام.

Example.Method(42);  // Method(int)
Example.Method(new Class1())  // Method<T>(T)

وهذا سوف دغة لك على الرغم من أنه هذا لا ينطبق عندما يتم استدعاء الأسلوب بشكل عام. في هذه الحالة فإنه سيتم ربط الزائد عام بغض النظر عن نوع.

public void Gotcha<T>(T value) {
  Example.Method(value);
}

Gotcha(42);  // Still calls Example.Method<T>()

و"التخصص" غير ممكن في C # على ما هو عليه في C ++. في الوراثة. NET، فئة عامة أو أسلوب يجب أن تكون هي نفسها لجميع القيم الممكنة من T. هذا يسمح للوقت للقيام أحد التحسينات الذي يقول نوعين مرجعية مختلفة، TestClass <سلسلة> وTestClass <قائمة <كثافة العمليات >>، وتقاسم نفس رمز لغة الآلة. (أنواع قيمة مختلفة الحصول على رمز الجهاز منفصل، ولكن كنت لا تزال لا يمكن متخصصون.)

وأجد أنه يساعد في بعض الأحيان لإنشاء واجهة عامة أو فئة أساسية من هذا القبيل:

abstract class Base<T> {
  public abstract T GetName();
  // any common code goes here that does not require specialization
}

والقيام التخصص في الفئات المشتقة:

class IntVersion : Base<int> {
  public override int GetName() { return 1; }
  public int GetName(int addNumber) { ... }
}
class StringVersion : Base<string> {
  public override string GetName() { return "foo"; }
}
class DateTimeVersion : Base<DateTime> {
  public override DateTime GetName() { return DateTime.Now; }
}

لا، هذا غير ممكن. ما تحاول القيام به هو مماثل لتخصص القالب في C ++، وهو (للأسف) غير ممكن في C #.

وتحتاج إلى إذا / آخر أو التبديل على

typeof(T)

واستدعاء التطبيقات المتخصصة.

ومع ذلك، يمكنك القيد نوع T إما أن تكون فئة (القيمة المرجعية) أو البنية (القيمة) أو فئة فرعية من معين baseclass مثل ذلك:

 public Foo<T> DoBar<T>() where T : FooBase;
لايوجد <ع> ج # دعم لهذا إيفاد.

وهذه ليست الطريقة الصحيحة للقيام طريقة التحميل الزائد أيضا (Error'TestClass 'يعرف عضو بالفعل يسمى' GetName "مع أنواع المعلمة نفسها) ما دام كل داخل <> ليست جزءا من توقيع الأسلوب.

هل استخدام طرق الإرشاد الطبقة عمل لك؟

ويمكنك إضافة أساسا الأساليب إلى الطبقات التي تريدها، ومن ثم يمكنك تسميتها بنفس الطريقة.

namespace ExtensionMethods
{
    public static class MyExtensions
    {
        public static int GetName(this String str)
        {
            ...
        }
    }   
}

ودعا باستخدام:

myString.GetName();

إذا كنت بحاجة إلى القيام بعمل من نوع معين في صفك، ثم صفك ليست عامة. ربما يجب عليك جعل فئة منفصلة لكل نوع تريد التعامل معها. إذا كان هناك بعض الوظائف التي لا يكون لديها سبب الصحيح لكونه عام، يمكنك وضعه في الفئة الأساسية المشتركة.

وعلى سبيل المثال:

abstract class TestClass<T>
{
    public List<T> Items { get; set; }

    // other generic (i.e. non type-specific) code
}

class IntTestClass : TestClass<int>
{
    public string GetName()
    {
        // do work knowing that the type is an int
    }

    // other code specific to the int case
}

class StringTestClass : TestClass<string>
{
    public string GetName()
    {
        // do work knowing that the type is a string
    }

    // other code specific to the string case
}

وكما ذكر BFree يمكنك القيام بذلك مع إن شجرة، أو على الأرجح بيان التبديل، ولكن في مرحلة ما عليك ترغب في أن مجرد كتابة أساليب والسماح صافي الرقم بها، وخاصة إذا كنت تنمو مكتبة الزائدة مع مرور الوقت.

والحل هو انعكاس هناك، على الرغم من أنها رخيصة جدا الأداء الحكمة في صافي:

using System.Reflection;
...

public string DoSomething(object val)
{
    // Force the concrete type
    var typeArgs = new Type[] { val.GetType() };

    // Avoid hard-coding the overloaded method name
    string methodName = new Func<string, string>(GetName).Method.Name;

    // Use BindingFlags.NonPublic instead of Public, if protected or private
    var bindingFlags = BindingFlags.Public | BindingFlags.Instance;

    var method = this.GetType().GetMethod(
        methodName, bindingFlags, null, typeArgs, null);

    string s = (string)method.Invoke(this, new object[] { val });

    return s;
}

وأنت في الأساس مجرد قول إطار انعكاس لتذهب تفعل هذا البيان التحول بالنسبة لك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top