Тривиальный класс C # с универсальным параметром не будет компилироваться без видимой причины - PullRequest
1 голос
/ 05 августа 2011

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

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

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

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

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

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

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

Ответы [ 7 ]

8 голосов
/ 05 августа 2011

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

  • использовать ограничение 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;
    }
};
4 голосов
/ 05 августа 2011

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

Чтобы иметь возможность вызвать 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;
    }
};
4 голосов
/ 05 августа 2011

Вы можете указать тип следующим образом:

internal class MyTemplate<WhatType> where WhatType : LeftInterface

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

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

public interface LeftInterface
{   
   int Left {get; set;}
}
2 голосов
/ 05 августа 2011

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

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

public interface IFoo
{
    int Left {get;}
}

и

* * 1010
1 голос
/ 05 августа 2011

Вы должны указать базовый класс, который поддерживает .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;    
    }

  }
  ...
0 голосов
/ 05 августа 2011

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

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

internal class MyTemplate<WhatType> where WhatType : BaseType {

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

0 голосов
/ 05 августа 2011

Эй, парень, тебе просто нужно это:

Принудительная реализация универсального интерфейса в C #

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...