开发者

Compile time error: cannot convert from specific type to a generic type

I get a compile time error with the following relevant code snippet at the line that calls NotifyObservers in the if construct.

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);
    }
}

The error I receive is:

The best overloaded method match for 'ExternalSystem.NotifyObservers(TEventArgs)' has some invalid arguments. Cannot convert from 'ExecutiveEventArgs' to 'TEventArgs'.

I am compiling this in C# 3.0 using Visual Studio 2008 Express Edition.

For now, I've gotten around the problem by branching out the specific object instantiation into overridden methods, like the snippet given below, but I am need to understand why the error occurred. I thought the compiler could infer the type hierarchy in the above situation.

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);
}

}


The TEventArgs generic parameter will be of some specific type, which is derived from EmployeeEventArgs, but the compiler doesn't know which exact type it will be until later. The compiler therefore can't allow the conversion, because it doesn't know whether it will be valid.

Just to clarify, if you create an object of type ExternalSystem<Janitor, JanitorEventArgs>, then TEventArgs will be JanitorEventArgs in the context of this object, and both calls to NotifyObservers will be invalid, because ExecutiveEventArgs does not derive from JanitorEventArgs.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜