2016-07-19 2 views
25

У меня около 1000 классов, в которых мне нужно подсчитать количество свойств. У меня есть следующий код:Как добавить метод расширения ко многим классам?

public static int NumberOfProperties() 
    { 
     Type type = typeof(C507); 
     return type.GetProperties().Count(); 
    } 

Я мог скопировать и вставить это в к каждому классу меняющегося параметра typeof, но это, кажется, немного утомительно.

Есть ли способ сделать способ расширения для этого, просто делая var nop = C507.NumberOfProperties();?

+22

Это, скорее всего, проблема XY. – OldFart

+8

В чем проблема, которую вы пытаетесь решить? Скорее всего, это не лучшее решение. –

+0

I *** очень *** надеюсь, что у вас нет 1000 классов с именем 'C000'' 'C999'! – Kroltan

ответ

22

невозможно иметь статический метод расширения, как вы себе Это. При этом можно было бы создать общий метод в вспомогательном классе следующим образом.

public static int NumberOfProperties<T>() 
{ 
    Type type = typeof(T); 
    return type.GetProperties().Count(); 
} 

Учитывая тип SomeType его можно было бы назвать, как int n = NumberOfProperties<SomeType>().

+2

Я немного смущен * Невозможно иметь статический метод расширения, как вы себе это представляете. *? Другие ответы, похоже, предполагают, что это вполне возможно. Я не понимаю? – Liam

+23

Codor ... ha awesome. – Liam

+3

@Liam: Хотя добавочный метод на 'object' вполне возможен, как показывают другие ответы, невозможно иметь его' static', чтобы можно было вызвать вызов типа SomeType.NumberOfProperties(). Для этого классы должны были бы основываться на том же базовом типе, в котором реализована логика отражения. – Codor

28

Таким образом, вы можете написать метод расширения, который использует объект или тот, который использует тип.

public static class ObjectExtensions 
{ 
    public static int GetNumberOfProperties(this object value) 
    { 
     return value.GetType().GetProperties().Count(); 
    } 

    public static int GetNumberOfProperties(this Type value) 
    { 
     return value.GetProperties().Count(); 
    } 
} 

Использование:

new C507().GetNumberOfProperties(); 
typeof(C507).GetNumberOfProperties(); 

Однако, вы явно указать две вещи:

Я мог скопировать и вставить в каждый класс меняя TYPEOF

I имеют около 1000 классов

Вы, вероятно, не хотят, чтобы создать экземпляр 1000 классов или копировать и вставлять typeof() 1000 раз

В этом случае, вы хотите, чтобы прочитать их все от Ассамблеи.

Так что-то вроде:

typeof(SomeClass).Assembly.GetTypes().Select(x => new 
    { 
     x.Name, 
     PropertyCount = x.GetType().GetProperties().Count() 
    }); 

SomeClass Где класс (не имеет значения, какой), где все классы проживают.

Я просто выделил их в анонимный объект, который содержит имя и количество типов.

Это:

typeof(SomeClass).Assembly 

Есть только convience способ получить сборку. Есть и другие способы.

Assembly.GetAssembly(typeof(Program)).GetTypes() 
Assembly.GetCallingAssembly().GetTypes() 
Assembly.Load("Some Assemble Ref").GetTypes() 

Вы можете делать сортировки по типам, которые вы найдете. Если вы выберете сам Type, вы можете создать его позже, используя Activator.CreateInstance (если у него есть без параметров constuctor). Вы также можете автоматически заполнять свойства отражением.

+0

Если они не хотят иметь количество свойств для каждого класса в сборке, они также могут написать атрибут «PropertyCountNeeded», применить его к классам, представляющим интерес, а затем фильтровать классы с этим свойством. –

+1

Да, абсолюти! Или еще лучше определить соглашение о названии класса. Это зависит. Я лично хотел бы сохранить эти 1000 классов в одной сборке. Но, к сожалению, так много выведенных из контекста трудно найти наилучшее возможное решение. Вещи вроде, почему у вас было 1000 классов для начала? –

+0

Если пример OP взят буквально, похоже, что у них уже есть соглашение об именах: 'C###'. –

9

Вы могли бы сделать метод расширения на object так:

public static int PropertyCount(this object thing) 
{ 
    return thing.GetType().GetProperties().Count(); 
} 

и использовать его на любом объекте вы хотите:

var x = "some string"; 
var numProps = x.PropertyCount(); 
6

Если вы хотите иметь метод расширения object:

public static ObjectExtensions 
{ 
    public static int NumberOfProperties(this object value) 
    { 
     if (null == value) 
      throw new ArgumentNullException("value"); // or return 0 

     // Length: no need in Linq here 
     return value.GetType().GetProperties().Length; 
    } 
} 

... 

C507 myObj = new C507(); 

// How many properties does myObj instance have? 
int propCount = myObj.NumberOfProperties(); 

Если вы хотите иметь метод extesnion на Type:

public static TypeExtensions 
    { 
     public static int NumberOfProperties(this Type value) 
     { 
      if (null == value) 
       throw new ArgumentNullException("value"); // or return 0 

      // Length: no need in Linq here 
      return value.GetProperties().Length; 
     } 
    } 

    ... 


    // How many properties does C507 type have? 
    int propCount = typeof(C507).NumberOfProperties(); 
44

Просто, чтобы добавить к ответам, предполагающим расширения для object для полноты: вы также можете рассмотреть возможность внедрения расширения только для Type:

public static int GetPropertyCount(this Type t) 
{ 
    return t.GetProperties().Length; 
} 

и использовать его как это:

typeof(C507).GetPropertyCount(); 

Преимущество заключается в том, что вы можете получить ряд свойств непосредственно от типа и не должны создавать экземпляр первого.

+0

Но это не решает проблему «Я мог бы скопировать и вставить это в каждый класс, изменяя параметр typeof, но это кажется немного утомительным». @EhsanSajjad –

+2

@CallumLinington это метод расширения, не нужно его копировать все классы. Вы должны выполнить его только один раз. В принятом ответе вы также должны называть его для каждого типа. 'typeof (C507) .GetPropertyCount()' для меня не выглядит более подробным, чем 'NumberOfProperties ()'. Вы должны изменить 'C507' для всех типов в обоих случаях. –

+0

Да, но вы реализуете его один раз и должны называть его «1000 классов». Таким образом, вы просто замыкаете 'GetProperties(). Count()', но сохраняя первоначальную проблему. Проблема вызова этого на 1000 классов. Возможно, OP может пролить больше света ... –

0

Вы можете сделать общий метод расширения, который может применяться ко всем типам:

public static int PropertyCount<T>(this T obj) 
{ 
    return typeof(T).GetProperties().Length; 
} 

Это будет применяться ко всем типам, включая типы значений (т.е. структуры), которые, претендующих на объект не будет. Благодаря piedar для указания моей ошибки здесь, применение к объекту все равно добавляет этот метод расширения к значениям типов.

+1

['ValueType'] (https: //msdn.microsoft.com/en-us/library/system.valuetype \ (v = vs.110 \) .aspx) уже происходит из 'Object'. Все структуры являются объектами. – piedar

1

Есть несколько способов сделать это, которые являются вариантами одной и той же вещи.

Вы можете передать тип в качестве аргумента метода:

public static class Helper { 
    public static int NumberOfProperties(Type type) 
    { 
     return type.GetProperties().Count(); 
    } 
} 

Что вы назвали бы так:

// Imagine you have a class called MyClass 
var result = Helper.NumberOfProperties(typeof(MyClass)); 

Вы можете использовать использовать общую систему в C# сделать синтаксис немного очиститель. Это будет выглядеть следующим образом:

public static class Helper { 
    // Notice the argument was removed and 
    // the use of the "generic" syntax <T> 
    public static int NumberOfProperties<T>() 
    { 
     var type = typeof(T); 
     return type.GetProperties().Count(); 
    } 
} 

И вы могли бы назвать это так:

var result = Helper.NumberOfProperties<MyClass>(); 

Вы также можете использовать «Расширения», которые позволяют назвать его, как если бы это был метод, который принадлежал ваши классы.

public static class Helper { 
    // notice the `this` keyword before the parameter 
    // this is what tells C# that this is an extension method 
    public static int NumberOfProperties<T>(this T @this) 
    { 
     var type = typeof(T); 
     return type.GetProperties().Count(); 
    } 
} 

Это позволит вызвать метод как это:

var instance = new MyClass(); 
var result = instance.NumberOfProperties(); 

В этом примере я использовал общий синтаксис, так что это относится к любому типу объекта. Если вы хотите ограничить его только объектами, которые наследуются от определенного интерфейса или базового класса, вы просто измените его на использование общего синтаксиса на использование базового класса/интерфейса.Как это:

public static class Helper { 
    // notice the type got changed from a generic <T> 
    // to specifying the exact class you want to "extend" 
    public static int NumberOfProperties(this MyBaseClass @this) 
    { 
     var type = typeof(T); 
     return type.GetProperties().Count(); 
    } 
} 

Как @ Rene-Фогта упомянутых вы также можете создать метод расширения, так что он расширяет тип Type вместо этого. См. Его ответ в этой теме: https://stackoverflow.com/a/38455233/984780

0

Если ваш класс может реализовать интерфейс, вы можете расширить этот интерфейс.

public interface IExtensible { 
} 

class C507 : IExtensible { 

} 

public static int NumberOfProperties(this IExtensible extensible) 
{ 
    Type type = extensible.GetType(); 
    return type.GetProperties().Count(); 
} 

С учетом того, что сотни классов (сгенерированных?) Выглядят как плохое решение для начала.

Смежные вопросы