Ошибка времени компиляции: невозможно преобразовать конкретный тип в универсальный тип - PullRequest
0 голосов
/ 31 мая 2010

Я получаю ошибку времени компиляции со следующим соответствующим фрагментом кода в строке, которая вызывает NotifyObservers в конструкции if.

public class ExternalSystem<TEmployee, TEventArgs> : ISubject<TEventArgs>
    where TEmployee : Employee
    where TEventArgs : EmployeeEventArgs
{
    protected List<IObserver<TEventArgs>> _observers = null;
    protected List<TEmployee> _employees = null;

    public virtual void AddNewEmployee(TEmployee employee)
    {
        if (_employees.Contains(employee) == false)
        {
            _employees.Add(employee);

            string message = FormatMessage("New {0} hired.", employee);

            if (employee is Executive)
                NotifyObservers(new ExecutiveEventArgs { e = employee, msg = message });
            else if (employee is BuildingSecurity)
                NotifyObservers(new BuildingSecurityEventArgs { e = employee, msg = message });
        }
    }

    public void NotifyObservers(TEventArgs args)
    {
        foreach (IObserver<TEventArgs> observer in _observers)
            observer.EmployeeEventHandler(this, args);
    }
}

Я получаю ошибку:

Лучший перегруженный метод соответствует 'ExternalSystem.NotifyObservers (TEventArgs)' имеет несколько неверных аргументов. Не могу преобразовать из ExecutiveEventArgs в 'TEventArgs'.

Я компилирую это в C # 3.0, используя Visual Studio 2008 Express Edition.

На данный момент я справился с этой проблемой, разветвив конкретную реализацию объекта в переопределенные методы, например фрагмент, приведенный ниже, но мне нужно понять, почему произошла ошибка. Я думал, что компилятор может определить иерархию типов в описанной выше ситуации.

public class ExternalSystem<TEmployee, TEventArgs> : ISubject<TEventArgs>
    where TEmployee : Employee where TEventArgs: EmployeeEventArgs
{

protected List<IObserver<TEventArgs>> _observers = null;
protected List<TEmployee> _employees = null;

protected virtual void AddNewEmployee(TEmployee employee)
{
    if (_employees.Contains(employee) == false)
    {
        _employees.Add(employee);

        string message = FormatMessage("New {0} hired.", employee);

        NotifyObservers(GetEventArgs(employee, message));
    }
}


protected virtual TEventArgs GetEventArgs(TEmployee employee, string message)
{
    return default(TEventArgs);
}

public void NotifyObservers(TEventArgs args)
{
    foreach (IObserver<TEventArgs> observer in _observers)
        observer.EmployeeEventHandler(this, args);
}
}

public class SecuritySystem : 
ExternalSystem<BuildingSecurity, BuildingSecurityEventArgs>
{
    public SecuritySystem() : base() { }

protected override BuildingSecurityEventArgs GetEventArgs(BuildingSecurity employee, string message)
{
    return new BuildingSecurityEventArgs { msg = message, e = employee };
}

public void HireSecurityGuard(BuildingSecurity buildingSecurity)
{
    this.AddNewEmployee(buildingSecurity);
}

public void FireSecurityGuard(BuildingSecurity buildingSecurity)
{
    this.TerminateEmployee(buildingSecurity);
}

}

1 Ответ

1 голос
/ 31 мая 2010

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

Просто чтобы уточнить, если вы создадите объект типа ExternalSystem<Janitor, JanitorEventArgs>, тогда TEventArgs будет JanitorEventArgs в контексте этого объекта, и оба вызова NotifyObservers будут недействительными, потому что ExecutiveEventArgs делает не выводится из JanitorEventArgs.

...