Тривиальный класс С# с общим параметром не будет компилироваться без видимых причин

58
6

Я хочу, чтобы общая функция работала с типами, имеющими Top, Bottom, Right и Rect свойства только для чтения. У меня много таких классов в сторонней библиотеке.


Я написал это:


internal class MyTemplate<WhatType> {
internal static void Work( WhatType what )
{
int left = what.Left;
}
};

и я ожидаю, что это сработает - эквивалентный код на С++ будет работать нормально. Однако объекты С#:


ошибка CS1061: "WhatType" не содержит определения для "Left" и не используется метод расширения "Left", принимающий первый аргумент типа "WhatType" (вам не хватает директивы использования или ссылки на сборку?)



Я не понимаю - почему он пытается создать экземпляр шаблона, прежде чем я его даже позвоню? Конечно, тип WhatType пока не известен и поэтому никаких свойств не найдено.


Что я делаю неправильно и как это исправить?

спросил(а) 2011-08-05T16:00:00+04:00 9 лет, 2 месяца назад
1
Решение
90

С# generics похожи на шаблоны С++, но на самом деле они совсем другие. С# generics строго типизированы, поэтому вы не можете вызвать элемент, который не известен статически.


Чтобы иметь возможность вызывать Left для объекта типа WhatType, вы должны указать, что WhatType реализует интерфейс или наследует от класса, который определяет Left, используя общее ограничение. Например:

interface IHasPosition
{
int Left { get; }
int Top { get; }
}

internal class MyTemplate<WhatType> where WhatType : IHasPosition
{
internal static void Work( WhatType what )
{
int left = what.Left;
}
};

ответил(а) 2011-08-05T16:05:00+04:00 9 лет, 2 месяца назад
121

Генераторы С# не являются шаблонами; они предоставляются во время выполнения, а не с помощью магии компилятора. Таким образом, нет утиного набора текста. Два варианта:


    используйте ограничение where WhatType : ISomeInterface, где ISomeInterface имеет Left {get;}
    используйте dynamic (который обеспечивает утиную печать)

то есть.

internal class MyTemplate<WhatType> where WhatType : ISomeInterface {
internal static void Work( WhatType what )
{
int left = what.Left;
}
};
interface ISomeInterface {
int Left { get; }
}

или


internal class MyTemplate<WhatType> {
internal static void Work( WhatType what )
{
int left = ((dynamic)what).Left;
}
};

ответил(а) 2011-08-05T16:03:00+04:00 9 лет, 2 месяца назад
92

Вы можете указать такой тип:


internal class MyTemplate<WhatType> where WhatType : LeftInterface

Затем вы можете использовать вызов .Left.


Где LeftInterface может выглядеть так:


public interface LeftInterface
{
int Left {get; set;}
}

ответил(а) 2011-08-05T16:03:00+04:00 9 лет, 2 месяца назад
70

Общие сведения используются для безопасности типов. Теперь, без дополнительной информации о WhatType, как компилятор узнает, что экземпляр what, который будет передан, будет иметь свойство Left?


Вам нужно что-то вроде этого


public interface IFoo
{
int Left {get;}
}

и


internal class MyTemplate<WhatType> where WhatType : IFoo {

ответил(а) 2011-08-05T16:04:00+04:00 9 лет, 2 месяца назад
58

Вы должны указать базовый класс, который поддерживает .Left в предложении where, или вам нужно указать, что относится к типу, который поддерживает свойство .Left:


internal class MyTemplate<WhatType> where WhatType : YourBaseClassWithLeftProperty

или


internal class MyTemplate<WhatType> {
internal static void Work( WhatType what ) {
YourBaseClassWithLeftProperty yourInstance=what as YourBaseClassWithLeftProperty;
if(null != yourInstance){
int left = yourInstance.Left;
}

}
...

ответил(а) 2011-08-05T16:04:00+04:00 9 лет, 2 месяца назад
41

Вы не указали никаких условий для типа WhatType, поэтому он будет принимать любой тип и знать только, что знает каждый тип, т.е. только то, что определено в классе Object.


Если вы хотите использовать что-либо еще в типе, вы должны указать, что он содержит, что вы делаете, указав, что он должен реализовать интерфейс или наследовать от класса:


internal class MyTemplate<WhatType> where WhatType : BaseType {

Где BaseType будет либо интерфейсом, либо классом, где определено свойство Left.

ответил(а) 2011-08-05T16:07:00+04:00 9 лет, 2 месяца назад
41

Эй, мальчик, тебе это просто нужно:


Внедрение универсального интерфейса в С#


таким образом вы можете предположить, что ваш экземпляр WhatType будет иметь Left, Bottom и т.д....

ответил(а) 2011-08-05T16:06:00+04:00 9 лет, 2 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема