Hacer que el campo de una clase no se pueda heredar y que al mismo tiempo sea...

Iniciado por z3nth10n, 15 Junio 2017, 00:21 AM

0 Miembros y 1 Visitante están viendo este tema.

z3nth10n

Hola buenas,

creo que he sido claro, no encuentro una respuesta, por lo que creo que no se puede, de hecho, creo que lo que formulo no tiene sentido. Dentro de mi cabeza sí.

Por ejemplo, tenemos:

Código (csharp) [Seleccionar]
public class Saludo
{

 public object tipo;
 private string cagonto;

}


Código (csharp) [Seleccionar]
public class Hola : Saludo
{

 public void Iniciar() {
   cagonto = ""; // CS0122, error de accesibilidad, lo que significa que es bien, en Intellisense no sale nada.
 }

}


Esta es la única forma de hacerlo, pero claro, esto significa que si quiero acceder desde fuera voy a tener que jartarme a metodos (si vengo de Java) o a propiedades en este caso, y es un poco coñazo, no hay ningún otro "estado de visibilidad (public, protected, internal, protected)" o a algún atributo que cumpla esto? Que no se pueda heredar, pero sin embargo, si de la posibilidad de ser accedido desde otra clase, ya sea por instancia o por acceso estático.

Gracias.

Un saludo.

PD: No es de vital urgencia, simplemente, es un mero hecho organizativo.

PD2: De hecho, lo propuesto no es una solución ni medio decente, pero al menos el iconito del Intellisente no me despista.



Ya veis, una variable/atributo es de color azul, mientras que una propiedad es gris y un método morado.

Interesados hablad por Discord.

Serapis

Cita de: Ikillnukes en 15 Junio 2017, 00:21 AM
creo que he sido claro, no encuentro una respuesta, por lo que creo que no se puede, de hecho, creo que lo que formulo no tiene sentido. Dentro de mi cabeza sí.

Pués no, no has sido claro.
Has escrito un título demasiado largo y no has reparado en que el foro, tiene un tamaño máximo y recorta el resto, lo que hace que tu pregunta no esté claramente expuesta (queda cortada).

¿y que al mismo tiempo sea...?

z3nth10n


Interesados hablad por Discord.

Eleкtro

Hola.

Primero de nada debemos aclarar que, hablando con propiedad de la palabra, un atributo de clase no es a lo que te refieres, sería esto otro:

Código (vbnet) [Seleccionar]
[ClassAtttibute()]
public class Class1 { }


...A lo que tú te refieres es a un campo o variable, en este caso.




Cita de: Ikillnukes en 15 Junio 2017, 00:21 AM
Esta es la única forma de hacerlo, pero claro, esto significa que si quiero acceder desde fuera voy a tener que jartarme a metodos o a propiedades en este caso, y es un poco coñazo

...¿Qué?. No se te entiende nada.  En el ejemplo que has puesto, la variable "cagonto" tiene un acceso privado, por ende solo es accesible a nivel de clase (la clase donde fue declarada esa variable), no es accesible desde ningún otro lugar como la clase "Hola" de tu ejemplo (a menos que utilices Reflection), lo cual es correcto, ya que no tendría sentido que fuese de otra manera.




Cita de: Ikillnukes en 15 Junio 2017, 00:21 AMHacer que el atributo de una clase no se pueda heredar y que al mismo tiempo sea accesible desde otras clases

No, así no es como trabaja la herencia, y no sería buena idea, y además iría en contra de los principios de la organización según mi opinión. En lugar de intentar prohibir la herencia, cosa que no puedes como lo quieres hacer, puedes considerar la idea de ocultar el miembro mediante los atributos DesignerSerializationVisibility, Browsable, y EditorBrowsable (según tus necesidades), pero a partir de la versión 2015 o 2017 de Visual Studio la aplicación de esos atributos no tendrá ningún efecto si estás trabajando directamente sobre el código fuente (es decir, los miembros no se ocultarán en tu código fuente, se ocultarían si trabajas con la clase/dll/exe compilada en un proyecto diferente que no sea el código fuente donde declaraste esos miembros, espero que se me entienda).

Lo que yo hago con miembros base que deben ser heredados obligatoriamente pero no necesitan ser consumidos y/o implementados por las clases derivadas (aunque siempre se pueden reimplementar y/o acceder a los miembros base si lo deseamos, así que no supone ningún impedimento), entonces los oculto en el editor de código y así me aseguro de que no se produce ningún fallo humano/intento de acceder a un miembro heredado de forma involuntaria (puesto que como ya digo, de forma voluntaria se puede acceder a ellos, solo que están ocultos, y eso siempre es un buen indicativo de que no se deberían usar...)

Te muestro un ejemplo sacado de mi framework de pago ElektroKit:

Código (csharp) [Seleccionar]
// ***********************************************************************
// Author   : Elektro
// Modified : 25-June-2016
// ***********************************************************************

#region " Imports "

using System.ComponentModel;

#endregion

#region " Aesthetic Object "

namespace Types {

/// ----------------------------------------------------------------------------------------------------
/// <summary>
/// This is a class to consume for aesthetic purposes.
/// <para></para>
/// A default (emptyness) class that inherits from <see cref="Object"/>, with these base members hidden:
/// <para></para>
/// <see cref="System.Object.GetHashCode"/>, <see cref="System.Object.GetType"/>,
/// <see cref="System.Object.Equals(Object)"/>, <see cref="System.Object.Equals(Object, Object)"/>,
/// <see cref="System.Object.ReferenceEquals(Object, Object)"/>, <see cref="System.Object.ToString()"/>.
/// </summary>
/// ----------------------------------------------------------------------------------------------------
public abstract class AestheticObject : object
{

#region " Hidden Base Members (of Object) "

[EditorBrowsable(EditorBrowsableState.Never)]
public virtual new int GetHashCode() {
return base.GetHashCode();
}

[EditorBrowsable(EditorBrowsableState.Never)]
public virtual new Type GetType() {
return base.GetType();
}

[EditorBrowsable(EditorBrowsableState.Never)]
public virtual new bool Equals(object obj) {
return base.Equals(obj);
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static new bool Equals(object objA, object objB) {
return object.Equals(objA, objB);
}

[EditorBrowsable(EditorBrowsableState.Never)]
public static new bool ReferenceEquals(object objA, object objB) {
return object.ReferenceEquals(objA, objB);
}

[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() {
return base.ToString();
}

#endregion

}

}

#endregion


Código original y documentado: AestheticObject.vb

Aparte, tampoco es una buena idea que declares una variable de tipo "Object" en una clase heredable si lo que te importa es ser eficiente y organizado, en su lugar puedes trabajar con una clase genérica y así asegurar que el tipo del objeto será reconocible en tiempo de ejecución:

Código (csharp) [Seleccionar]
public class GenericClass<T> {

public readonly T Obj;

private GenericClass() { }

public GenericClass(T type) {
this.Obj = type;
}

}


Código (csharp) [Seleccionar]
public sealed class InheritedClass : GenericClass<Color> {

public InheritedClass(Color value) : base(value) { }

}


Código (csharp) [Seleccionar]
GenericClass instance = new GenericClass(Color.Red);
Debug.WriteLine(instance.Obj.GetType().FullName);


O bien esto otro (lo que viene a ser lo mismo, pero para distinto uso):

Código (csharp) [Seleccionar]
public sealed class GenericClass<T> {

public readonly T Obj;

public GenericClass(T obj) {
this.Obj = obj;
}

}


Código (csharp) [Seleccionar]
GenericClass<Color> instance = new GenericClass<Color>(Color.Red);
Debug.WriteLine(instance.Obj.GetType().FullName);


Saludos!








z3nth10n

*****, vaya lío formé anoche, si me refería a un campo. Y estaba buscando un atributo, porque por lo veo no se puede hacer de otra forma.

Me viene de lujo, puesto que yo estoy haciendo una API pero para Unity, o sea, que estoy compilando todo en una librería.

Eso del objeto, me lo dices porque tipo del campo de la clase Saludo es un objeto?

Un saludo.

Interesados hablad por Discord.

Eleкtro

Cita de: Ikillnukes en 15 Junio 2017, 13:53 PMEso del objeto, me lo dices porque tipo del campo de la clase Saludo es un objeto?

Sí, me refería al tipo de esta variable:
Citar
Código (csharp) [Seleccionar]
public object tipo

En C#, tomar el hábito de usar "var" y/o "object" no es buena idea de organización, aunque en C# todos los objetos son asignados mediante early binding (a diferencia de VB.NET, que te permite elegir el modo de enlazamiento de objetos), pero el problema es que hacer eso no permite reconocer el tipo específico de un objeto si la intención es ser productivo programando y saber el tipo de "X" con tan solo mirar el nombre mientras trabajas en tu código fuente, es necesario examinar el objeto en lugar del nombre del tipo ("object") o el keyword "var", por ende si la intención es ser perfeccionista para organizar y tener un código "entendible" entonces hacer eso es todo lo opuesto a organización.

Supongo que esto que voy a decir ya lo sabrás, pero ten en cuenta que el tipo object (System.Object) es la clase base o herencia implícita en todas las demás clases existentes en la librería de .NET Framework, o dicho de otra forma todos los tipos de objetos son del tipo object en última instancia, por ende no puedes conocer el tipo específico del objeto declarado con solo mirar el nombre si no lo especificas al momento de declararlo, y eso pues rompe los principios de tener un código organizado... en mi opinión.

Por supuesto siempre hay excepciones, no digo que no, las hay, y según para qué propósito pues puede que la solución más productiva sea declarar un objeto del tipo object (sin ir más lejos vease la propiedad Tag de algunos controles de WinForms), pero por lo general no suele ser así.

Too long / don't read:

...Del mismo modo que tampoco sería buena idea activar el late binding en VB.NET (en C# esto no es posible), puesto que son todo desventajas, empezando por que da lugar a posibles fallos humanos de sintaxis que no serán detectados en tiempo de compilación sino en tiempo de ejecución... lo que causará excepciones al usar el programa y dificultará la depuración del código fuente por que el error no se detectará en tiempo de compilación como ya he dicho.

Un objeto se debe asignar a una variable declarada que sea de un tipo específico, siempre, no importa si estamos en C# o en VB.NET, en C# por productividad/organización y en VB.NET por lo mismo y por evitar fallos; a esto se le llama early binding como ya dije, y esa es la forma optimizada y ventajosa de programar, ya que aparte de evitar convertirnos en programadores con malos hábitos y evitar cualquier posible fallo humano de sintaxis (ya que un error será detectado al momento en tiempo de compilación), estarás ayudando al compiler y al JIT puesto que los objetos o declaraciones early bound permiten al compiler asignar memoria y realizar otras optimizaciones antes de que una aplicación ejecute, y así también estarás siendo estrictamente organizado, productivo, y eficiente.

Saludos!