Подтвердить что ты не робот

Общий с несколькими классами

Я пытаюсь создать этот общий метод для упрощения, но, думаю, я испортил его! Можете ли вы помочь с моей проблемой?

Это компилируется:

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Supplier, new()
    where T1 : Employee, new()
    where T2 : SupplierDepartment, new()
    where T2 : EmployeeDepartment, new()
{
    T1 p = new T1();
    T2 r = new T2();
    //Code here for myEntity treatment
    return mystring;
}

Пока это не компилируется:

protected void mybutton1_Click(object sender, EventArgs e)
{
   string mystring = ConcatenaText<Supplier, SupplierDepartment>(myEntity);
}

//This does not compile
protected void mybutton2_Click(object sender, EventArgs e)
{
   string mystring = ConcatenaText<Employee, EmployeeDepartment>(myEntity);
}

Сообщение: Поставщик типа не может использоваться как параметр типа T1 в общем типе или методе ConcatenateText (MyEntity myEntity). Нет никакого неявного преобразования ссылок от Поставщика к Сотруднику

Можно ли это сделать? Что я делаю не так? Можно ли улучшить?

EDIT:

И MyEntity - это еще один класс, чтобы обработать его внутри этого общего метода! Это не связано с типами Т. Это просто аргумент. Но ясно, что я не могу этого сделать, используя 2 типа. Я думал, что могу назначить то или другое, и CLR независимо от моей инициализации может реагировать так, как я хотел. Я собираюсь принять ответ, который делится немного дополнительной информацией об этом.

4b9b3361

Ответ 1

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

where T1 : Supplier, new()
where T1 : Employee, new()

со следующей ошибкой:

Условие ограничения уже указано для параметра типа "T1". Все ограничения для параметра типа должны быть указаны в одном предложении where.

В качестве статей статьи MSDN вы можете использовать только одно ограничение "where" для каждого общего параметра (см. http://msdn.microsoft.com/en-us/library/bb384067.aspx).

"С несколькими параметрами типа используйте одно предложение where для каждого параметра типа..."

Вы также не можете поместить несколько имен классов в одно ограничение 'where'. Только одно имя класса и несколько интерфейсов.

where T1 : Supplier, IContractor, IComparable, new()

Имейте в виду, что это ограничение диктует, что фактический тип, который вы предоставляете в качестве общего параметра T1, должен быть преемником самого класса поставщика или самого поставщика. И он должен реализовать интерфейсы IContractor AND IComparable.

Как только ваш метод примет объект MyEntity, и вы не укажете, какое отношение оно имеет к классам Employee и Supplier, я не могу догадаться, как этот класс MyEntity знает о классах Employee and Supplier и как это отношение помогает вам.

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

class Program
{
    static void Main(string[] args)
    {
        Method1<Employee>();
        Method1<Supplier>();
    }

    private static void Method1<T1>()
        where T1 : IContractor, new()
    {

    }
}

public class Supplier : IContractor
{
    string IContractor.Name
    {
        get{return "Employee name";}
    }
}

public class Employee : IContractor
{
    string IContractor.Name
    {
        get{return "Customer name";}
    }
}

public interface IContractor
{
    string Name
    {
        get;
    }
}

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

Создайте перегруженный метод для каждого из таких типов.

Представьте, что у вас есть два класса: Wife и Wine. Оба имеют атрибут Age и того же типа. Но даже не думайте о создании общего интерфейса IAged для этих классов. Суть классов и смысл Age настолько различны, что их никогда не следует унифицировать. Тем не менее, некоторая общая логика вполне может вам помочь. Например:

private double AgeQualify(Wife someWife)
{
    return 1 / (someWife.Age * someWife.Beachness);
}

private double AgeQualify(Wine someWine)
{
    return someWine.Age / someWine.Sugar;
}

Ответ 2

Вам либо нужно сделать отдельные версии:

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Supplier, new()
    where T2 : SupplierDepartment, new()  
{
    T1 p = new T1();
    T2 r = new T2();
    return mystring;
}

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : Employee, new()
    where T2 : EmployeeDepartment, new()
{
    T1 p = new T1();
    T2 r = new T2();
    return mystring;
}

или нужно сделать им общий базовый класс:

private string ConcatenateText<T1, T2>(MyEntity myEntity) 
    where T1 : EmployeeSuplierBase, new()
    where T2 : EmployeeSupplierDeparmentBase, new()
{
    T1 p = new T1();
    T2 r = new T2();
    return mystring;
}

Я бы предпочел отдельные версии, потому что с ними они не могут называть его Supplier и EmployeeDeparment (или наоборот)

Ответ 3

Вы действительно не должны использовать дженерики в этом случае. Есть только два варианта.

Итак:

string ConcatenateText(Supplier Entity) { ...code...} 
string ConcatenateText(Employee Entity) { ...code...}  

Что вы можете сделать, это унифицировать как базовый класс, концентрирующий все распространенные методы.

Скажем, если у поставщика и сотрудника есть Name:

class BaseClass
{
    public string Name {get; set;}
}

class Employee : BaseClass
{
    //emplyee stuff except name and other things already in base
}

class Supplier : BaseClass
{
    //supplier stuff except name and other things already in base
}

И затем, метод принимает BaseClass:

private string ConcatenateText(BaseClass Entity) 
{ 
    //code
}